POJ 3278 Catch That Cow java 二分法 加 組合算法

原題:
http://poj.org/problem?id=3278

二分法一年前就寫出來了,但是提交代碼出現Wrong Answer,不知道什麼問題,自己跑隨機測試又沒問題,一年之後提交,竟然過了,java類別下排名40,還不錯

在這裏插入圖片描述

現在把測試方法和代碼分享一下

一般都是用廣度搜索解決,個人感覺這種方法效率太差,考慮用二分法,但是有些情況要處理,比如奇數不能直接二分,要走一步才能分,怎麼走這一步?減法不一定是最短距離,有些奇數加1能直接二分多次,比減法更快,比如1到15,減法:14 7 6 3 2 1共6步,加法:16 8 4 2 1共5步;要找出其中的數學規律很難,就把所有組合列出來然後考慮一下邊界問題就行了,這種方法跑隨機數據,每一組數據的結果都是1ms以內,而bfs基本都是1ms以上的,效率提升還是很明顯的

這個是提交代碼:

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while (sc.hasNextInt()) {
			int n = sc.nextInt();
			int k = sc.nextInt();
			int sum = 0;
			sum = test(n, k);
			System.out.println(sum);
		}
	}

	private static int getMinSpace(List<Line> jumpMove, int N, int K) {
		int minSpace = 0;
		for (int i = 0; i < jumpMove.size(); i++) {
			Line l = jumpMove.get(i);
			if (l.listStep.size() > 0) {
				Integer lastN = l.listStep.get(l.listStep.size() - 1);
				int timeStep = l.listStep.size() + Math.abs(lastN - N);
				if (minSpace == 0 || timeStep < minSpace) {
					minSpace = timeStep;
				}
			} else {
				minSpace = Math.abs(K - N);
			}
		}
		return minSpace;
	}

	public static List jumpMove(Integer K, int N, List<Line> list, int index, Line line) {
		// 跳轉次數
		for (int i = 1; (K / 2 != 0 && N <= K / 2)
				|| (N >= K / 2 && K / 2 != 0 && (K - N) > (N - (K / 2))); i++) {
			line.time = i;
			if (K % 2 == 1) {
				Line l = new Line();
				l.time = i;
				l.listStep.addAll(line.listStep);
				l.listStep.add(K + 1);
				jumpMove(K + 1, N, list, index + 1, l);
				line.listStep.add(K - 1);
			}
			K = K / 2;
			line.listStep.add(K);
		}
		list.add(line);
		return list;
	}

	/**
	 * 牛的步數進行二分,然後農夫往最近的二分點上靠
	 * 
	 * @param n
	 *            農夫
	 * @param k
	 *            牛
	 */
	public static int test(int N, int K) {
		int t = 0;
		if (N > K) {
			t = N - K;
		} else if (N == K) {
			t = 0;
		} else {
			ArrayList<Line> linkedList = new ArrayList<Line>();
			Line line = new Line();
			List<Line> jumpMove = jumpMove(K, N, linkedList, 0, line);
			t = getMinSpace(jumpMove, N, K);
		}
		return t;
	}

	static class Line {
		// 傳送次數
		public int time;
		// 步法集合
		public List<Integer> listStep = new ArrayList<Integer>();
	}
}

這個是測試代碼,可以和bfs方法相驗證,也可以行走打印路徑:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

public class Test1 {
	public static void main(String[] args) {
		// Scanner sc = new Scanner(System.in);
		// while (sc.hasNext()) {
		// int n = 33;
		// int k = 23493; //
		// int sum = 0;
		//
		// System.out.println( bfs(n, k));
		// }
		int time = 100000000;
		for (int i = 0; i < time; i++) {
			Random rand = new Random();
			int n = rand.nextInt(100000);
			int k = rand.nextInt(100000);
			// int n = i;
			// for (int j = 0; j < 100000; j++) {
			// int k = j;
			long start = System.currentTimeMillis();
			int sum2 = splitUnit(n, k);
			long end = System.currentTimeMillis();
			System.out.println("my======" + (end - start) + "   sum===" + sum2);
			long start2 = System.currentTimeMillis();
			int sum = bfs(n, k);
			long end2 = System.currentTimeMillis();
			System.out.println("bsf======" + (end2 - start2) + "   sum===" + sum);
			// if (j % 100 == 0) {
			// System.out.println("i=" + i + " n=" + n + " k=" + k);
			// }
			if (sum2 != sum ) {
				// j = 1000000;
				i = time;
				System.err.println("n:" + n + " k:" + k + " sum:" + sum + " sum2:" + sum2 );
			}
			// }
			// System.out.println("i=" + i+" n="+n+" k="+k );
			// System.out.print(n+" "+k +" ");

		}
	}

	private static int getMinSpace(List<Line> jumpMove, int N, int K) {
		int minSpace = 0;
		for (int i = 0; i < jumpMove.size(); i++) {
			Line l = jumpMove.get(i);
			if (l.listStep.size() > 0) {
				Integer lastN = l.listStep.get(l.listStep.size() - 1);
				int timeStep = l.listStep.size() + Math.abs(lastN - N);
				if (minSpace == 0 || timeStep < minSpace) {
					minSpace = timeStep;
				}
				// System.out.print(l.time+" list.size=="+l.listStep.size()+"
				// ");
				// for (int j = 0; j < l.listStep.size(); j++) {
				// Integer integer = l.listStep.get(j);
				// System.out.print(integer+" ");
				// }
			} else {
				minSpace = Math.abs(K - N);
			}
		}
		return minSpace;
	}

	public static List jumpMove(Integer K, int N, List<Line> list, int index, Line line) {
		// 跳轉次數
		for (int i = 1; (K / 2 != 0 && N <= K / 2) || (N >= K / 2 && K / 2 != 0 && (K - N) > (N - (K / 2))); i++) {
			line.time = i;
			// System.out.println(K1);
			if (K % 2 == 1) {
				// System.err.println("space K=="+K);
				Line l = new Line();
				l.time = i;
				l.listStep.addAll(line.listStep);
				l.listStep.add(K + 1);
				jumpMove(K + 1, N, list, index + 1, l);
				line.listStep.add(K - 1);
				// System.err.println(K1);
			}
			K = K / 2;
			line.listStep.add(K);
			// if (N >= K1 / 2 && (K1 - N) > (N - (K1 / 2))) {
			// line.time = i + 1;
			// K1 = K1 / 2;
			// line.listStep.add(K1);
			// }
		}
		list.add(line);
		// System.out.println(list.size() + " " + list.get(0).listStep.size());
		return list;
	}

	/**
	 * 牛的步數進行二分,然後農夫往最近的二分點上靠
	 * 
	 * @param n
	 *            農夫
	 * @param k
	 *            牛
	 */
	public static int splitUnit(int N, int K) {
		int t = 0;
		if (N > K) {
			t = N - K;
		} else if (N == K) {
			t = 0;
		} else {
			LinkedList<Line> linkedList = new LinkedList<Line>();
			Line line = new Line();
			List<Line> jumpMove = jumpMove(K, N, linkedList, 0, line);
			t = getMinSpace(jumpMove, N, K);
		}
		// System.out.println(t);
		return t;
	}

	static class Line {
		// 傳送次數
		public int time;
		// 步法集合
		public List<Integer> listStep = new LinkedList<>();
	}

	public static int bfs(int n, int k) {
		Queue que = new Queue();
		Node node = new Node();
		Boolean vis[] = new Boolean[400001];
		for (int i = 0; i < vis.length; i++) {
			vis[i] = false;
		}
		int sum = 0;
		node.step = 0;
		node.num = n;
		que.push(node);
		vis[n] = true;
		int sumaa = 0;
		while (que.size() > 0) {
			sumaa = sumaa + 1;
			// 3 5 8 2 4 6 4 6 10 7 9 12
			Node temp = (Node) que.remove();
			if (temp.num == k) {
				sum = temp.step;
				// System.out.println("size=====" + temp.listStep.size());
				// for (int i = 0; i < temp.listStep.size(); i++) {
				// System.out.println(" " + temp.listStep.get(i));
				// }
				break;
			}
			int t = temp.num;
			// System.out.println("t=="+t);
			if (t - 1 >= 0 && !vis[t - 1]) {
				Node te = new Node();
				te.num = t - 1;
				te.step = temp.step + 1;
				// te.listStep.add(te.num);
				// te.listStep.addAll(temp.listStep);
				que.push(te);
				vis[te.num] = true;
			}
			if (t + 1 < 200000 && !vis[t + 1]) {
				Node te = new Node();
				te.num = t + 1;
				te.step = temp.step + 1;
				// te.listStep.add(te.num);
				// te.listStep.addAll(temp.listStep);
				que.push(te);
				vis[te.num] = true;
			}
			if (2 * t < 200000 && !vis[2 * t]) {
				Node te = new Node();
				te.num = t * 2;
				te.step = temp.step + 1;
				// te.listStep.add(te.num);
				// te.listStep.addAll(temp.listStep);
				que.push(te);
				vis[te.num] = true;
				// System.out.println(temp.step + " " + temp.num + " " +
				// temp.step + " sumaa==" + sumaa);
			}

		}
		// System.out.println("-----n:" +n+" k:"+k+ " "+ que.size());
		return sum;
	}

}
class Queue {
	List list = new ArrayList();

	public void push(Object obj) {
		list.add(obj);
	}

	public Object remove() {
		if (list.size() > 0) {
			return list.remove(0);
		} else {
			return null;
		}
	}

	public int size() {
		return list.size();
	}
}

class Node {
	Integer num;
	Integer step;
	// List<Integer> listStep = new LinkedList<Integer>();
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章