隐式图的遍历
采用广度优先搜索的算法,从当前节点front扩展出所有可能的节点。扩展就是从一个杯子的水往另外一个杯子里面倒。
首先需要判断一下可以倒多少水,从第i个杯子往第j个杯子里面倒,如果第i个杯子有L升,第j个杯子有K升,则第j个杯子还能容纳cap[j]-K升,cap为容量。
倒完后用vis数组判重。只需要开两个状态即可,即第一个和第二个杯子的倒水量,重了就不扩展,不重的话就入队进行扩展。
AC代码:
#include<iostream>
#include<cstring>
using namespace std;
#define Max 201
struct Node{
int volume[3];
int amount;
};
int cap[3],flag;
int d,front,rear;
int vis[Max][Max];
Node q[Max*Max];
void bfs(void){
int i,j,amount,k;
q[0].volume[0]=q[0].volume[1]=q[0].amount=0;
q[0].volume[2]=cap[2];
vis[0][0]=1;
front=0,rear=1;
while(front<rear){
Node &now=q[front];
if(now.volume[0]==d||now.volume[1]==d||now.volume[2]==d){
flag=1;
return ;
}
for(i=0;i<3;i++){
for(j=0;j<3;j++){
if(i!=j){
Node &next=q[rear];
amount=now.volume[i]<(cap[j]-now.volume[j])?now.volume[i]:cap[j]-now.volume[j];
for(k=0;k<3;k++)
next.volume[k]=now.volume[k];
next.volume[i]-=amount;
next.volume[j]+=amount;
if(!vis[next.volume[1]][next.volume[2]]){
vis[next.volume[1]][next.volume[2]]=1;
next.amount=now.amount+amount;
rear++;
}
}
}
}
front++;
}
}
int main()
{
int i,j,test_case;
cin >>test_case;
while(test_case--){
flag=0;
memset(vis,0,sizeof(vis));
for(i=0;i<3;i++)
cin>>cap[i];
cin>>d;
bfs();
if(flag==1){
cout << q[front].amount << " " << d << endl;
}
else{
for(i=d-1;i>=0;i--){
for(j=0;j<=rear;j++){
if(q[j].volume[0]==i||q[j].volume[1]==i||q[j].volume[2]==i){
flag=1;
break;
}
}
if(flag)
break;
}
cout << q[j].amount <<" " <<i<<endl;
}
}
return 0;
}