NYOJ21 三个水杯

来源:互联网 发布:2017年网络剧 编辑:程序博客网 时间:2024/05/16 00:41

题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=21
题目分析:
暴力+BFS。将所有可能的状态压到队列中,直到找到目标状态为止。
我自己AC的代码。

#include<stdio.h>#include<string.h>//三个水杯的盛水的状态struct Node{int a;//水杯1的水量int b;//水杯2的水量int c;//水杯3的水量int flag;};Node queue[100];bool used[101][101][101];inline void Pour(Node p,int &tail){if(!used[p.a][p.b][p.c]){queue[++tail] = p;used[p.a][p.b][p.c] = true;}}inline int min(const int a, const int b){return a < b ? a :b;}//寻找倒水路径int PourWaterTwo(int *goal, int *vol){int head = 0;int tail = 0;int temp;Node s,p;while(head <= tail){s = queue[head];//将1倒入2或3中if(s.a > 0){if(s.b < vol[1]){temp = min(vol[1] - s.b , s.a);p.a = s.a - temp;p.b = s.b + temp;p.c = s.c;p.flag = s.flag + 1;if(p.a == goal[0] && p.b == goal[1] && p.c == goal[2])return p.flag;Pour(p,tail);}if(s.c < vol[2]){temp = min(vol[2] - s.c , s.a);p.a = s.a - temp;p.b = s.b;p.c = s.c + temp;p.flag = s.flag + 1;if(p.a == goal[0] && p.b == goal[1] && p.c == goal[2])return p.flag;Pour(p,tail);}}//将2倒入1或3中if(s.b > 0){if(s.a < vol[0]){temp = min(vol[0] - s.a , s.b);p.a = s.a + temp;p.b = s.b - temp;p.c = s.c;p.flag = s.flag + 1;if(p.a == goal[0] && p.b == goal[1] && p.c == goal[2])return p.flag;Pour(p,tail);}if(s.c < vol[2]){temp = min(vol[2] - s.c , s.b);p.a = s.a;p.b = s.b - temp;p.c = s.c + temp;p.flag = s.flag + 1;if(p.a == goal[0] && p.b == goal[1] && p.c == goal[2])return p.flag;Pour(p,tail);}}if(s.c > 0)//将3倒入1,2中{if(s.a < vol[0]){temp = min(vol[0] - s.a , s.c);p.a = s.a + temp;p.b = s.b;p.c = s.c - temp;p.flag = s.flag + 1;if(p.a == goal[0] && p.b == goal[1] && p.c == goal[2])return p.flag;Pour(p,tail);}if(s.b < vol[1]){temp = min(vol[1] - s.b , s.c);p.a = s.a;p.b = s.b + temp;p.c = s.c - temp;p.flag = s.flag + 1;if(p.a == goal[0] && p.b == goal[1] && p.c == goal[2])return p.flag;Pour(p,tail);}}++head;}return -1;}int main(){int goal[3];int vol[3];int t;scanf("%d", &t);queue[0].b = 0;queue[0].c = 0;queue[0].flag = 0;while(t--){memset(used,0,sizeof(used));scanf("%d %d %d", &vol[0], &vol[1], &vol[2]);scanf("%d %d %d",&goal[0], &goal[1], &goal[2]);queue[0].a = vol[0];used[vol[0]][0][0] = true;if(goal[0] + goal[1] + goal[2] != vol[0]){printf("-1\n");continue;}if(goal[0] == vol[0] && !goal[1] && !goal[2]){printf("0\n");continue;}printf("%d\n",PourWaterTwo(goal,vol));}}

OJ上的最优代码,当时我写的时候就在想怎么优化,其实想到了一点点,不过还是太弱了,最终没有搞出来。看看大牛的作品。

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<bitset> using namespace std; #define CLR(arr,val) memset(arr,val,sizeof(arr)) bitset<1000000> Hash; const int MAX_STEP=100000; int WQ[MAX_STEP][4],Goal[3],Cap[3],goalval; int head=0,tail=0; void movw(int numfrom,int numto,int other) {     int total=WQ[head][numfrom]+WQ[head][numto];     WQ[tail][other]=WQ[head][other];     WQ[tail][3]=WQ[head][3]+1;     if(total>Cap[numto])     {         WQ[tail][numfrom]=total-Cap[numto];         WQ[tail][numto]=Cap[numto];     }     else     {         WQ[tail][numfrom]=0;         WQ[tail][numto]=total;     }     int hashval=WQ[tail][0]*10000+WQ[tail][1]*100+WQ[tail][2];     if(hashval==goalval) throw WQ[head][3]+1;     if(WQ[head][numfrom]!=0 && !Hash[hashval])      {         Hash[hashval]=true;         if(++tail==MAX_STEP) tail=0;     } } int main() {     int t;     scanf("%d",&t);     while(t--)     {         Hash.reset();         scanf("%d%d%d%d%d%d",&Cap[0],&Cap[1],&Cap[2],&Goal[0],&Goal[1],&Goal[2]);         head=0,tail=0,goalval=Goal[0]*10000+Goal[1]*100+Goal[2];         if(Goal[1]==0 && Goal[2]==0 && Goal[0]==Cap[0]) {puts("0");continue;}         WQ[tail][0]=Cap[0];WQ[tail][1]=0;WQ[tail][2]=0;WQ[tail][3]=0;         ++tail;         try{             while(head!=tail)             {                 movw(0,1,2);movw(1,2,0);movw(0,2,1);movw(1,0,2);movw(2,1,0);movw(2,0,1);                 if(++head==MAX_STEP) head=0;             }             puts("-1");         }catch(int step)         {             printf("%d\n",step);         }     } }
原创粉丝点击