NYOJ-三个水杯

Posted 赤云封天

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NYOJ-三个水杯相关的知识,希望对你有一定的参考价值。

题目网址:

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 }

 

以上是关于NYOJ-三个水杯的主要内容,如果未能解决你的问题,请参考以下文章

NYOJ-三个水杯

nyoj 21 三个水杯

nyoj 21-三个水杯(BFS)

NYOJ21.三个水杯-初始态到目标态的最少次数-经典BFS

三个水杯

三个水杯(BFS)