三个水杯acm c语言,NYOJ-三个水杯-DFS and BFS解法

题目连接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=21php

如下图片参考此微博,谢谢:https://blog.csdn.net/guozlh/article/details/50572347ios

三个水杯相互倒水的过程以下:spa

a98328b87f4c48d3b44670f231eaa59a.gif

对于每一次倒水都会引发三个水杯水量状态的改变,这样就能够获得以下的一个解空间树:

.net

a98328b87f4c48d3b44670f231eaa59a.gif

DFS-AC代码以下:code

#include

#include

#include

#include

#include

#include

#include

#define INF 1e8

using namespace std;

int v1,v2,v3,e1,e2,e3,vis[105][105],m;//标记某个肯定的序列,而且记录他的步数。。。真的应该用bfs写,干吗折腾本身

void dfs(int a, int b, int c,int count)

{

if(a == e1 && b == e2)

{

if(count < m)

{

m = count;

}

}

//dfs访问的是全解,第一次访问到的并非最短的。

if(!vis[a][b] || vis[a][b] > count)//若是第一次访问该序列的步数大于第二次访问该序列的步数

{

vis[a][b] = count;//则选择第二次的步数

//模拟倒水的过程

if(a != 0)

{

if(b != v2)

dfs(a>(v2-b) ? a-(v2-b):0, a>(v2-b) ? v2:a+b, c, count+1);

if(c != v3)

dfs(a>(v3-c) ? a-(v3-c):0, b, a>(v3-c) ? v3:a+c, count+1);

}

if(b != 0)

{

if(a != v1)

dfs(b>(v1-a) ? v1:a+b, b>(v1-a) ? b-(v1-a):0, c, count+1);

if(c != v3)

dfs(a, b>(v3-c) ? v3:b+c, b>(v3-c) ? b-(v3-c):0, count+1);

}

if(c != 0)

{

if(a != v1)

dfs(c>(v1-a) ? v1:a+c, b, c>(v1-a) ? c-(v1-a):0, count+1);

if(b != v2)

dfs(a, c>(v2-b) ? v2:b+c, b>(v2-b) ? c-(v2-b):0, count+1);

}

}

}

//搜索:在不少数据中不断地重复一个类似的动做寻找正确答案,首先要抽象地全面的扩充数据。

int main()

{

int t;

scanf("%d",&t);

while(t--)

{

m = INF;

memset(vis,0,sizeof(vis));

scanf("%d%d%d",&v1,&v2,&v3);

scanf("%d%d%d",&e1,&e2,&e3);

dfs(v1,0,0,0);

if(m == INF)

printf("-1\n");

else

printf("%d\n",m);

}

return 0;

}

BFS-AC代码以下:blog

#include

#include

#include

#include

#include

#include

#include

using namespace std;

struct Node{

int a,b,c,step;

};

int v1,v2,v3,e1,e2,e3,vis[105][105];

int bfs(int a,int b,int c)

{

Node p;

p.a = a;

p.b = b;

p.c = c;

p.step = 0;

queue q;

q.push(p);

int count = 0;

while(!q.empty())

{

Node temp = q.front();

q.pop();

if(temp.a == e1 && temp.b == e2)

{

count = temp.step;

break;

}

int x = min(v2 - temp.b,temp.a);

if(x >= 0)

{

Node y;

y.a = temp.a-x;

y.b = temp.b+x;

y.c = temp.c;

y.step = temp.step+1;

if(!vis[y.a][y.b] && y.a >= 0 && y.b >= 0 && y.c >= 0)//在减的过程当中,可能出现小于零的状况

{

vis[temp.a][temp.b] = 1;

q.push(y);

}

}

x = min(v3 - temp.c,temp.a);

if(x >= 0)

{

Node y;

y.a = temp.a-x;

y.b = temp.b;

y.c = temp.c+x;

y.step = temp.step+1;

if(!vis[y.a][y.b] && y.a >= 0 && y.b >= 0 && y.c >= 0)

{

vis[temp.a][temp.b] = 1;

q.push(y);

}

}

x = min(v1 - temp.a,temp.b);

if(x >= 0)

{

Node y;

y.a = temp.a+x;

y.b = temp.b-x;

y.c = temp.c;

y.step = temp.step+1;

if(!vis[y.a][y.b] && y.a >= 0 && y.b >= 0 && y.c >= 0)

{

vis[temp.a][temp.b] = 1;

q.push(y);

}

}

x = min(v3 - temp.c,temp.b);

if(x >= 0)

{

Node y;

y.a = temp.a;

y.b = temp.b-x;

y.c = temp.c+x;

y.step = temp.step+1;

if(!vis[y.a][y.b] && y.a >= 0 && y.b >= 0 && y.c >= 0)

{

vis[temp.a][temp.b] = 1;

q.push(y);

}

}

x = min(v1 - temp.a,temp.c);

if(x >= 0)

{

Node y;

y.a = temp.a+x;

y.b = temp.b;

y.c = temp.c-x;

y.step = temp.step+1;

if(!vis[y.a][y.b] && y.a >= 0 && y.b >= 0 && y.c >= 0)

{

vis[temp.a][temp.b] = 1;

q.push(y);

}

}

x = min(v2 - temp.b,temp.c);

if(x >= 0)

{

Node y;

y.a = temp.a;

y.b = temp.b+x;

y.c = temp.c-x;

y.step = temp.step+1;

if(!vis[y.a][y.b] && y.a >= 0 && y.b >= 0 && y.c >= 0)

{

vis[temp.a][temp.b] = 1;

q.push(y);

}

}

}

if(count == 0 && (a != e1 || b != e2 || c != e3))

return -1;

else

return count;

}

int main()

{

int n;

scanf("%d",&n);

while(n--)

{

scanf("%d%d%d",&v1,&v2,&v3);

scanf("%d%d%d",&e1,&e2,&e3);

memset(vis,0,sizeof(vis));

int ans = bfs(v1,0,0);

printf("%d\n",ans);

}

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值