题目网址:
http://acm.nyist.net/JudgeOnline/problem.php?pid=21
这道题做了三天,内心是痛苦的。几次想到放弃,但是又不忍心现有的成果,又不想借鉴别人的代码。我相信我可以。就坚持下来了。最后也通过了。做这道题的感想就是流泪并快乐着。或许这也就是acmer的乐趣吧。
这道题收获是巨大的。过后看网上说就是队列 + 搜索。我感觉则不然。我认为他是搜索 + 半个动态规划。为什么这么说呢?
1.队列的作用在这儿就是达到递归的效果。然而我就用递归的方式实现它,这点可以忽略。概括之,就是搜索的应用。
2.开始的时候,我只是单纯的递归去做,结果对,但是超时了(后面有超时的代码)。这里就需要用到动规的知识了。即把每一个已求得的状态到终态的距离保存下,以后会大量用到,这样就不用接着递归下去了。省了很多时间。
具体思路是这样的:
总共就6种情况:A->B A->C B->A B->C C->A C->B。用递归搜索的经典形式:边界条件 + for循环。
不断地对当前状态到终态的距离进行更新。当存在一个更小的距离时,就更新。最后的state[A][0][0]就是最后结果。需要注意的是:代码的第31行,要保证将要出现的状态没有在递归的过程中(从初态到现在这一个分支)出现过,不然就会陷入死循环。程序的146行也是个关键点:当递归返回时,上层状态到终态的距离需要下一层的加1 ,牵强的说成这是状态转移方程吧(至少有相似之处,细细品味)。is_exist数组记录的是:从初态到当前状态的这个分支中是否出现过。
超时代码:这种情况没有进行状态保存
1 #include <stdio.h> 2 typedef struct { 3 int A,B,C; 4 }State; 5 State remember[1000]; 6 int top; 7 int capacity_A,capacity_B,capacity_C; 8 int e1,e2,e3; 9 int cnt; 10 11 int judge(int a,int b,int c){ 12 for(int i = top-1; i >= 0; i--){ 13 if(a == remember[i].A && b == remember[i].B && c == remember[i].C){ 14 return 0; 15 } 16 } 17 return 1; 18 } 19 20 void DFS(int a,int b,int c){ 21 if(a == e1 && b == e2 && c == e3){///递归边界 22 if(cnt > top-1) 23 cnt = top-1; 24 top--; 25 return ; 26 } 27 28 State cur; 29 30 for(int i = 0; i < 6; i++){ 31 int t;/// * -> *的水量 32 switch (i){ 33 case 0:///A->B 34 if(a != 0 && capacity_B - b != 0){///B杯未满 35 if(a >= capacity_B - b){///A杯水量超过B杯剩余空间 36 t = capacity_B - b; 37 }else{ 38 t = a; 39 } 40 if(judge(a-t, b+t, c)){ 41 remember[top].A = a-t; remember[top].B = b+t; remember[top].C = c; 42 top++; 43 DFS(a-t, b+t, c); 44 } 45 46 } 47 break; 48 case 1:///A->C 49 if(a != 0 && capacity_C - c != 0){///C杯未满 50 if(a >= capacity_C - c){///A杯水量超过C杯剩余空间 51 t = capacity_C - c; 52 }else{ 53 t = a; 54 } 55 if(judge(a - t,b,c + t)){///这种状态没有出现过 56 remember[top].A = a-t; remember[top].B = b; remember[top].C = c+t; 57 top++; 58 DFS(a - t,b,c + t); 59 } 60 } 61 break; 62 case 2:///B->A 63 if(b != 0 && capacity_A - a != 0){///a杯未满 64 if(b >= capacity_A - a){///B杯水量超过A杯剩余空间 65 t = capacity_A - a; 66 }else{ 67 t = b; 68 } 69 if(judge(a+t,b-t,c)){///这种状态没有出现过 70 remember[top].A = a+t; remember[top].B = b-t; remember[top].C = c; 71 top++; 72 DFS(a+t,b-t,c); 73 } 74 } 75 break; 76 case 3:///B->C 77 if(b != 0 && capacity_C - c != 0){///c杯未满 78 if(b >= capacity_C - c){///B杯水量超过C杯剩余空间 79 t = capacity_C - c; 80 }else{ 81 t = b; 82 } 83 if(judge(a, b-t, c+t)){///这种状态没有出现过 84 remember[top].A = a; remember[top].B = b-t; remember[top].C = c+t; 85 top++; 86 DFS(a, b-t, c+t); 87 } 88 } 89 break; 90 case 4:///C->A 91 if(c != 0 && capacity_A - a != 0){///a杯未满 92 if(c >= capacity_A - a){///C杯水量超过A杯剩余空间 93 t = capacity_A - a; 94 }else{ 95 t = c; 96 } 97 if(judge(a+t, b, c-t)){///这种状态没有出现过 98 remember[top].A = a+t; remember[top].B = b; remember[top].C = c-t; 99 top++; 100 DFS(a+t, b, c-t); 101 } 102 } 103 break; 104 case 5:///C->B 105 if(c != 0 && capacity_B - b != 0){///b杯未满 106 if(c >= capacity_B - b){///C杯水量超过B杯剩余空间 107 t = capacity_B - b; 108 }else{ 109 t = c; 110 } 111 if(judge(a, b+t, c-t)){///这种状态没有出现过 112 remember[top].A = a; remember[top].B = b+t; remember[top].C = c-t; 113 top++; 114 DFS(a, b+t, c-t); 115 } 116 } 117 break; 118 } 119 } 120 top--; 121 } 122 123 int main(){ 124 int N; 125 scanf("%d",&N); 126 while(N--){ 127 scanf("%d%d%d%d%d%d",&capacity_A,&capacity_B,&capacity_C,&e1,&e2,&e3); 128 cnt = 60000; 129 State cur; 130 cur.A = capacity_A; cur.B = cur.C = 0; 131 remember[top++] = cur; 132 DFS(capacity_A,0,0); 133 if(cnt == 60000) 134 printf("-1\n"); 135 else 136 printf("%d\n",cnt); 137 } 138 return 0; 139 }
Accept代码:
1 #include <stdio.h> 2 int capacity_A,capacity_B,capacity_C; 3 int e1,e2,e3; 4 int cnt; 5 int state[100][100][100];///记录状态到终态的记录,默认为INF 6 int is_exist[100][100][100];///记录是否是递归过后的状态 7 8 int DFS(int a,int b,int c){ 9 is_exist[a][b][c] = 1; 10 if(a == e1 && b == e2 && c == e3){///递归边界 11 state[a][b][c] = 0; 12 return 0; 13 } 14 15 for(int i = 0; i < 6; i++){ 16 int t;/// * -> *的水量 17 switch (i){ 18 case 0:///A->B 19 if(a != 0 && capacity_B - b != 0){///B杯未满 20 if(a >= capacity_B - b){///A杯水量超过B杯剩余空间 21 t = capacity_B - b; 22 }else{ 23 t = a; 24 } 25 if(state[a-t][b+t][c] < 60000){ 26 if(state[a][b][c] > state[a-t][b+t][c] + 1){ 27 state[a][b][c] = state[a-t][b+t][c] + 1;///旧状态 28 break; 29 } 30 } 31 if(is_exist[a-t][b+t][c] == 0){///60000新状态 ///没有在递归过程中出现过 32 int cur = DFS(a-t, b+t, c); 33 if(state[a][b][c] > cur+1) 34 state[a][b][c] = cur + 1; 35 } 36 37 } 38 break; 39 case 1:///A->C 40 if(a != 0 && capacity_C - c != 0){///C杯未满 41 if(a >= capacity_C - c){///A杯水量超过C杯剩余空间 42 t = capacity_C - c; 43 }else{ 44 t = a; 45 } 46 if (state[a-t][b][c+t] < 60000){ 47 if(state[a][b][c] > state[a-t][b][c+t] + 1){ 48 state[a][b][c] = state[a-t][b][c+t] + 1; 49 break; 50 } 51 } 52 if(is_exist[a-t][b][c+t] == 0){///没有在递归过程中出现过 53 int cur = DFS(a-t,b,c+t); 54 if(state[a][b][c] > cur+1) 55 state[a][b][c] = cur + 1; 56 } 57 58 } 59 break; 60 case 2:///B->A 61 if(b != 0 && capacity_A - a != 0){///a杯未满 62 if(b >= capacity_A - a){///B杯水量超过A杯剩余空间 63 t = capacity_A - a; 64 }else{ 65 t = b; 66 } 67 if(state[a+t][b-t][c] < 60000){ 68 if(state[a][b][c] > state[a+t][b-t][c] + 1){ 69 state[a][b][c] = state[a+t][b-t][c] + 1; 70 break; 71 } 72 } 73 if(is_exist[a+t][b-t][c] == 0){///没有在递归过程中出现过 74 int cur = DFS(a+t,b-t,c); 75 if(state[a][b][c] > cur+1) 76 state[a][b][c] = cur+1; 77 } 78 79 } 80 break; 81 case 3:///B->C 82 if(b != 0 && capacity_C - c != 0){///c杯未满 83 if(b >= capacity_C - c){///B杯水量超过C杯剩余空间 84 t = capacity_C - c; 85 }else{ 86 t = b; 87 } 88 if(state[a][b-t][c+t] < 60000){ 89 if(state[a][b][c] > state[a][b-t][c+t] + 1){ 90 state[a][b][c] = state[a][b-t][c+t] + 1; 91 break; 92 } 93 } 94 if(is_exist[a][b-t][c+t] == 0){ 95 int cur = DFS(a,b-t,c+t); 96 if(state[a][b][c] > cur+1) 97 state[a][b][c] = cur+1; 98 } 99 100 } 101 break; 102 case 4:///C->A 103 if(c != 0 && capacity_A - a != 0){///a杯未满 104 if(c >= capacity_A - a){///C杯水量超过A杯剩余空间 105 t = capacity_A - a; 106 }else{ 107 t = c; 108 } 109 if(state[a+t][b][c-t] < 60000){ 110 if(state[a][b][c] > state[a+t][b][c-t] + 1){ 111 state[a][b][c] = state[a+t][b][c-t] + 1; 112 break; 113 } 114 } 115 if(is_exist[a+t][b][c-t] == 0){ 116 int cur = DFS(a+t,b,c-t); 117 if(state[a][b][c] > cur+1) 118 state[a][b][c] = cur+1; 119 } 120 121 } 122 break; 123 case 5:///C->B 124 if(c != 0 && capacity_B - b != 0){///b杯未满 125 if(c >= capacity_B - b){///C杯水量超过B杯剩余空间 126 t = capacity_B - b; 127 }else{ 128 t = c; 129 } 130 if(state[a][b+t][c-t] < 60000){ 131 if(state[a][b][c] > state[a][b+t][c-t] + 1){ 132 state[a][b][c] = state[a][b+t][c-t] + 1; 133 break; 134 } 135 } 136 if(is_exist[a][b+t][c-t] == 0){ 137 int cur = DFS(a,b+t,c-t); 138 if(state[a][b][c] > cur+1) 139 state[a][b][c] = cur+1; 140 } 141 142 } 143 break; 144 } 145 } 146 return state[a][b][c]; 147 } 148 149 int main(){ 150 int N; 151 scanf("%d",&N); 152 while(N--){ 153 scanf("%d%d%d%d%d%d",&capacity_A,&capacity_B,&capacity_C,&e1,&e2,&e3); 154 ///初始化state数组 155 for(int i = 0; i < 100; i++) 156 for(int j = 0; j < 100; j++) 157 for(int k = 0;k < 100; k++){ 158 state[i][j][k] = 60000; 159 is_exist[i][j][k] = 0; 160 } 161 162 state[capacity_A][0][0] = 61000; is_exist[capacity_A][0][0] = 1; 163 DFS(capacity_A,0,0); 164 if(state[capacity_A][0][0] >= 60000) 165 printf("-1\n"); 166 else 167 printf("%d\n",state[capacity_A][0][0]); 168 } 169 return 0; 170 }