1. 程式人生 > >倒水問題 (FillUVa 10603) 隱式圖

倒水問題 (FillUVa 10603) 隱式圖

names ++ () pen 尋找 min 如果 cnblogs spa

技術分享

題意:本題的題意是給你三個杯子,第一二個杯子是空的,第三個杯子裝滿水,要求是量出一定容量d升的水。若是得不到d升的水,那就讓某一個杯子裏面的水達到d‘,使得d‘盡量接近d升。

解題思路:本題是給出初始狀態,讓你尋找一條通往目標的路徑,此題也可看成是有向圖中在起點和目標點之間尋找一條最短路徑,但是這個最短路徑不是距離最短而是倒的水最少,所以這題類似於Dijkstra算法求最短路,利用廣搜,一直選當前水量最少的結點進行擴展,所以可以建立一個優先隊列來存儲下一次要訪問的結點,同時將訪問過的結點標記一下,大大節省了訪問時間,此題的結點數最多為201^2.

代碼:

 1 #include<stdio.h>
 2
#include<math.h> 3 #include<queue> 4 #include<string.h> 5 #include<iostream> 6 using namespace std; 7 const int maxn=205; 8 int n; 9 int visit[maxn][maxn],cap[3],ans[maxn]; 10 //三個數組分別表示標記是否訪問過這種情況,三個容器的大小,以及得到對應的水需要倒水的體積 11 12 struct Node{ 13 int v[3],dist; 14 const
bool operator < (Node s) const{ //優先隊列重載運算符 15 return dist>s.dist; 16 } 17 }; 18 19 void update(Node t){ //更新倒水數 20 for(int i=0;i<3;i++){ 21 int s=t.v[i]; 22 if(ans[s]<0 || t.dist<ans[s]){ 23 ans[s]=t.dist; 24 } 25 } 26 } 27 28
void traver(int a,int b,int c,int d){ //遍歷函數 29 priority_queue<Node> q; 30 memset(visit,0,sizeof(visit)); 31 memset(ans,-1,sizeof(ans)); 32 cap[0]=a; 33 cap[1]=b; 34 cap[2]=c; 35 Node s; 36 s.v[0]=0; 37 s.v[1]=0; 38 s.v[2]=c; 39 s.dist=0; 40 q.push(s); 41 visit[0][0]=1; 42 while(!q.empty()){ 43 Node t=q.top(); 44 q.pop(); 45 update(t); 46 if(ans[d]>=0) break; 47 for(int i=0;i<3;i++){//訪問下一個結點,表示將水從i杯倒到j杯 48 for(int j=0;j<3;j++){ 49 if(i!=j){ 50 if(t.v[i]==0||t.v[j]==cap[j]) continue; 51 Node k; 52 int water=min(t.v[i],cap[j]-t.v[j]); 53 k.dist=t.dist+water; 54 k.v[i]=t.v[i]-water; 55 k.v[j]=t.v[j]+water; 56 k.v[3-i-j]=t.v[3-i-j]; //如果不是講原結點復制過來的,記得給此結點賦值 57 if(!visit[k.v[0]][k.v[1]]){ 58 visit[k.v[0]][k.v[1]]=1; 59 q.push(k); 60 } 61 } 62 } 63 } 64 } 65 for(;d>=0;d--){    //輸出 66 if(ans[d]>=0){ 67 printf("%d %d\n",ans[d],d); 68 break; 69 } 70 } 71 } 72 73 int main(){ 74 freopen("in.txt","r",stdin); 75 scanf("%d",&n); 76 while(n--){ 77 int a,b,c,d; 78 scanf("%d%d%d%d",&a,&b,&c,&d); 79 traver(a,b,c,d); 80 } 81 return 0; 82 }

倒水問題 (FillUVa 10603) 隱式圖