倒水问题(Fill,UVA 10603) lrj白书 p202
看着lrj的代码自己敲了一遍,还没调试成功。。。。
有时间再进行完善
/* 状态start到各个状态u1,u2,u3..... 的倒水量分别为u1.dist,u2.dist,u3.dist.... */ /* 按倒水量递增的顺序去寻找当前状态的v[0],v[1],v[2]是否为d 但是程序实现的时候我们寻找目标水量是根据 ans[d]>0,而不是对每一个状态的v[]进行遍历 为什么这样做呢?当然是因为麻烦,ans[d]>0很直接地说明了v[]有三者之一为d */ #include <cstdio> #include <cstring> #include <queue> using namespace std; struct Node{ int v[3],dist; bool operator <(const Node &u) const{ return dist >u.dist; } }; const int maxn=200+5; int vis[maxn][maxn],cap[3],ans[maxn];//因为只有三只杯子,所以记录前两只杯子的状态即可 void update_ans(const Node &u){ for (int i=0;i<3;i++){ int d=u.v[i]; if(ans[d]<0||u.dist<ans[d]) ans[d]=u.dist;//每次有新的状态时,记录形成d升水所需要的最小倒水量 } } void solve(int a,int b,int c,int d){ cap[0]=a; cap[1]=b; cap[2]=c; memset(vis,0,sizeof(vis));//vis[]记录三元组状态是否重复 memset(ans,-1,sizeof(ans));//ans[]记录当前的最小倒水量 priority_queue<Node> q; Node start; start.dist=0;//总的倒水量 start.v[0]=0;start.v[1]=0;start.v[2]=c; q.push(start);//准备工作 vis[0][0]=1;//设置初始状态为已访问 /*!当所有状态都被访问完,就算ans[d]<0,while{}也停止 !!当ans[d]>0,表示输出所求的状态已找到,停止循环*/ while (!q.empty()){ Node u=q.top();q.pop();//对优先队列表头(即当前队列结点.dist最小)的结点进行访问 update_ans(u); if (ans[d]>=0) break; //从v[i]--v[j]加水,加多少水呢?只要能加,就加到不能加为止 for(int i=0;i<3;i++) for(int j=0;j<3;j++)if(i!=j){ if(u.v[i]==0||u.v[j]==cap[j]) continue; //过渡到下一个i或下一个j int amount=min(cap[j],u.v[i])-u.v[j]; Node u2; memcpy(&u2,&u,sizeof(u)); u2.dist=u.dist+amount; u2.v[i]-=amount; u2.v[j]+=amount; if (!vis[u2.v[0]][u2.v[1]]){ vis[u2.v[0]][u2.v[1]]=1; q.push(u2); } } } while (d>=0){ if(ans[d]>=0){ printf("%d %d\n",ans[d],d); return; } d--; } } int main(){ int T,a,b,c,d; scanf("d%",&T); while(T--){ scanf("%d%d%d%d",&a,&b,&c,&d); solve(a,b,c,d); } return 0; }
认准了,就去做,不跟风,不动摇