倒水问题简述就是 假设有3个杯,每个杯子的范围是(0,1000)
然后互相倒来倒去,最后得到一个结果为t的杯子,当然得不到也是可能的。
本来的可能状态总数为1000*1000*1000的话,是肯定爆掉的。
但是由于水总数不变,所以只要由中杯和小杯建立vis表就可以了。总可以这么转化。
以三杯水分别最大为6,3,1,初始时为6,0,0示例程序
#include <stdio.h>
#include <string.h>
struct CUP{
int maxv;
}cup[3];
struct STATE{
int d[3];
}state[10000],state2[10000];
int ans;
int vall;
char v[1003][1003];//分别为中杯和小杯
__inline int min(int a,int b){
return a<b?a:b;
}
int bfs(int d,int pre){
int len = 0,i,j,k,t1,t;
char a[3],as;
for(i = 0; i < pre; i++){
for(j = 0; j < 3;j++)
for(k = 0; k < 3; k++){
if(j == k)
continue;
if(state[i].d[j] != 0 && state[i].d[k] != cup[k].maxv){//判断可以移动的状态
t1 = min(state[i].d[j],cup[k].maxv - state[i].d[k]);
state2[len].d[j] = state[i].d[j] - t1;
state2[len].d[k] = state[i].d[k] + t1;
a[0] = a[1] = a[2] =1;
a[j] = a[k] = 0;
for(t = 0 ; t < 3; t++)//找到未替换的
if(a[t]){
as = t;
break;
}
state2[len].d[as] = state[i].d[as];
if(state2[len].d[0] == 4 || state2[len].d[1] == 4 || state2[len].d[2] == 4){
puts("find at ");
printf("%d\n",d);
return true;
}
if(v[state2[len].d[1]][state2[len].d[2]])
continue;
else {
v[state2[len].d[1]][state2[len].d[2]] = 1;
len ++;
}
}
}
}
memcpy(state,state2,sizeof(state2[0])*len);
if(len != 0)
return bfs(d+1,len);
else return false;
}
int main(){
cup[0].maxv = 6;
cup[1].maxv = 3;
cup[2].maxv = 1;
ans = 4;
memset(v,0,sizeof(v));
state[0].d[0] = 6;
state[0].d[1] = state[0].d[2] = 0;
vall = 6;
bfs(1,1);
return 0;
}