原題:
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>();
}