NYOJ21 三個水杯 (經典問題 bfs)
2014年12月21日 22:26:46
閱讀數:1278
題目描述:
轉載地址https://blog.csdn.net/fool_ran/article/details/42065653
給出三個水杯,大小不一,並且只有最大的水杯的水是裝滿的,其餘兩個爲空杯子。三個水杯之間相互倒水,並且水杯沒有標識,只能根據給出的水杯體積來計算。現在要求你寫出一個程序,使其輸出使初始狀態到達目標狀態的最少次數。
輸入
第一行一個整數N(0<N<50)表示N組測試數據
接下來每組測試數據有兩行,第一行給出三個整數V1 V2 V3 (V1>V2>V3 V1<100 V3>0)表示三個水杯的體積。
第二行給出三個整數E1 E2 E3 (體積小於等於相應水杯體積)表示我們需要的最終狀態
輸出
每行輸出相應測試數據最少的倒水次數。如果達不到目標狀態輸出-1
樣例輸入
2 6 3 1 4 1 1 9 3 2 7 1 1
樣例輸出
3 -1
題目分析:
經典題目,bfs搜索,不用回溯,直接暴力即可。
AC代碼:
-
/** *bfs,隱式圖的搜索 */ #include<iostream> #include<cstdio> #include<map> #include<cstring> #include<string> #include<algorithm> #include<queue> #include<vector> #include<stack> #include<cstdlib> #include<cctype> #include<cstring> #include<cmath> using namespace std; int vis[101][101][101];//記錄是否被訪問 struct StateNode{ int cur[3];//記錄當前狀態 int v[3];//記錄狀態 int step;//步數 }; queue<StateNode> q; int Sucess(StateNode a,StateNode b){//比較是否相等 return (a.cur[0] == b.cur[0] && a.cur[1] == b.cur[1] && a.cur[2] == b.cur[2]); } int main() { int t,res; StateNode b,e; cin>>t; while(t--){ res=-1; while(!q.empty()){//清空隊列 q.pop(); } cin>>b.v[0]>>b.v[1]>>b.v[2]; //下面開始模擬倒水,並搜索 b.cur[0]=b.v[0];//首先先給最大的水杯倒滿水 b.cur[1]=b.cur[2]=0;//小杯子爲0 b.step=0;//記錄步數 cin>>e.cur[0]>>e.cur[1]>>e.cur[2]; int ok=0;//記錄是否可以到達結尾狀態 memset(vis,0,sizeof(vis)); q.push(b);//加入隊列 vis[b.cur[0]][b.cur[1]][b.cur[2]]=1;//已經在訪問或者已經訪問 while(!q.empty()){//進行廣搜 StateNode u=q.front(); //cout<<u.cur[0]<<" "<<u.cur[1]<<" "<<u.cur[2]<<endl; q.pop(); if(Sucess(u,e)){//成功並結束 res=u.step; break; } //else 模擬倒水 for(int i=0;i<=2;i++){//用每一個被子給其他兩個被子倒水 for(int j=0;j<=2;j++){ if(i!=j){ int minv=u.v[j]-u.cur[j];//從當前狀態到被子倒滿,需要的水 if(u.cur[i]<minv){//當前的水小於需要的水,則能用的水變爲當前的水 minv=u.cur[i]; } //出現新節點 StateNode v=u; v.cur[i]-=minv;//必須先減去 v.cur[j]+=minv; v.step=u.step+1;//更新步數 //cout<<u.step<<endl; if(!vis[v.cur[0]][v.cur[1]][v.cur[2]]){//該結點沒有被訪問 q.push(v);//加入隊列 vis[v.cur[0]][v.cur[1]][v.cur[2]]=1;//已訪問 } } } } } cout<<res<<endl; } return 0; }