タイトル
水を注ぐ問題「Aを充填」はAカップを充填することを意味し、「空のA」はAカップを空にすることを意味します。入力に複数のデータセットが含まれています。データ入力の各セットA、B、Cデータ範囲0 <A <= B、C <= B <= 1000、AおよびBは比較的素数で、プログラムの出力は一連の命令で構成されます。これらの出力ラインにより、どのタンクにも正確にCユニットの水が収容されます。各データセットの最後の行の出力は「成功」であるはずです。出力行は列1から始まり、空白行や末尾のスペースがあってはなりません。
アイデア
これは典型的な暗黙のグラフ問題です。各カップについて、状態を変更するための6つの代替操作があります。これは、完全な6分岐ツリーと同等です。このツリーをトラバースして、必要なCを見つけます。ここでは、広域探索であり、次のレイヤーのポイントを計算しながら探索します。
アクセスパスは、定数配列のインデックスを格納する方法をここで使用しています。操作を行わずに文字列の最後にインデックスを追加します。出力時に文字列のみを文字でトラバースする必要があります
まとめ
ここでのキューの実装は、非キュー形式でも解決できます。大きな配列を開くと、2つのカーソルの相対位置を使用して、キューが空であるかどうかが判断され、同じ効果が得られます
コード
#include<stdio.h>
#include<string>
#include<string.h>
#include<iostream>
#include<queue>
using namespace std;
int ca,cb,n;
bool vis[4000][4000];
struct cup{
int a,b;
string s;//存储路径
cup(){}
cup(int qa,int qb,string ss){
a=qa;
b=qb;
s=ss;
}
};
queue<cup> qu;
string caozuo[6]={"fill A","empty A","fill B","empty B","pour A B","pour B A"};
void bfs(){
qu.push(cup(0,0,string()));
vis[0][0]=1;
while(!qu.empty()){
int a=qu.front().a;
int b=qu.front().b;
string s=qu.front().s;
qu.pop();
if(b==n||a==n){ //特判终点
for(int i=0;i<s.size();i++){//输出路径
cout<<caozuo[s[i]-48]<<endl;
}
cout<<"success"<<endl;
return;
}
if(!vis[ca][b]){// fill A
qu.push(cup(ca,b,s+"0"));
vis[ca][b]=1;
}
if(!vis[0][b]){//empty A
qu.push(cup(0,b,s+"1"));
vis[0][b]=1;
}
if(!vis[a][cb]){//fill B
qu.push(cup(a,cb,s+"2"));
vis[a][cb]=1;
}
if(!vis[a][0]){//empty B
qu.push(cup(a,0,s+"3"));
vis[a][0]=1;
}
int c=a+b>cb?cb:a+b;//pulll A B
if(!vis[a+b-c][c]){//B中水量可能满也可能不满
qu.push(cup(a+b-c,c,s+"4"));
vis[a+b-c][c]=1;
}
c=a+b>ca?ca:a+b; //pull B A
if(!vis[c][a+b-c]){//A中水量可能满也可能不满
qu.push(cup(c,a+b-c,s+"5"));
vis[c][a+b-c]=1;
}
}
return;
}
int main() {
while(~scanf("%d%d%d",&ca,&cb,&n)){
memset(vis,0,sizeof(vis));
while(!qu.empty())qu.pop();//多组数据将队列置空
bfs();
}
return 0;
}