HDU1495 非常可乐(模拟,广搜BFS)

来源:互联网 发布:登录阿里云 编辑:程序博客网 时间:2024/04/29 12:10

题目:

非常可乐

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 12407    Accepted Submission(s): 4950


Problem Description
大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。
 

Input
三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。
 

Output
如果能平分的话请输出最少要倒的次数,否则输出"NO"。
 

Sample Input
7 4 34 1 30 0 0
 

Sample Output
NO3
 

Author
seeyou
 

Source
“2006校园文化活动月”之“校庆杯”大学生程序设计竞赛暨杭州电子科技大学第四届大学生程序设计竞赛
 

Recommend
LL
 

Statistic | Submit | Discuss | Note
思路:

一共有六种情况,都列出来进行广搜,为了这道题我找bug找了两个小时,具体就不说了,都是泪哭,一定要注意细节。。

代码:

#include <stdio.h>#include <string.h>#include <iostream>#include <stack>#include <queue>#include <vector>#include <algorithm>#define mem(a,b) memset(a,b,sizeof(a))using namespace std;int s,n,m;int vis[105][105];struct node{    int s,a,b,t;//分别代表当前的可乐,a杯,b杯.和当前倒了的次数} ;int bfs(){    node now,to;    queue<node>q;    mem(vis,0);    now.s=s,now.a=0,now.b=0,now.t=0;    q.push(now);    vis[now.a][now.b]=1;    while(!q.empty())    {        now=q.front();        q.pop();        if(now.a==s/2 && now.s==s/2)return now.t;//满足可乐的量一样,返回步数        //分六种情况,导入另一个杯子        if(now.s&&now.a!=n)//s->a        {            int c=n-now.a;            if(now.s>=c)to.a=n,to.s=now.s-c;            else to.a=now.a+now.s,to.s=0;            to.b=now.b;            to.t=now.t+1;            if(!vis[to.a][to.b])            {                q.push(to);                vis[to.a][to.b]=1;            }        }        if(now.s&&now.b!=m)//s->b        {            int c=m-now.b;            if(now.s>=c)to.b=m,to.s=now.s-c;            else to.b=now.b+now.s,to.s=0;            to.a=now.a;            to.t=now.t+1;            if(!vis[to.a][to.b])            {                q.push(to);                vis[to.a][to.b]=1;            }        }        if(now.a&&now.s!=s)//a->s        {            int c=s-now.s;            if(now.a>=c)to.s=s,to.a=now.a-c;            else to.s=now.a+now.s,to.a=0;            to.b=now.b;            to.t=now.t+1;            if(!vis[to.a][to.b])            {                q.push(to);                vis[to.a][to.b]=1;            }        }        if(now.a&&now.b!=m)//a->b        {            int c=m-now.b;            if(now.a>=c)to.b=m,to.a=now.a-c;            else to.b=now.b+now.a,to.a=0;            to.s=now.s;            to.t=now.t+1;            if(!vis[to.a][to.b])            {                q.push(to);                vis[to.a][to.b]=1;            }        }        if(now.b&&now.a!=n)//b->a        {            int c=n-now.a;            if(now.b>=c)to.a=n,to.b=now.b-c;            else to.a=now.b+now.a,to.b=0;            to.s=now.s;            to.t=now.t+1;            if(!vis[to.a][to.b])            {                q.push(to);                vis[to.a][to.b]=1;            }        }        if(now.b&&now.s!=s)//b->s        {            int c=s-now.s;            if(now.b>=c)to.s=s,to.b=now.b-c;            else to.s=now.s+now.b,to.b=0;            to.a=now.a;            to.t=now.t+1;            if(!vis[to.a][to.b])            {                q.push(to);                vis[to.a][to.b]=1;            }        }    }    return 0;}int main(){    while(scanf("%d%d%d",&s,&n,&m)&&(s||n||m))    {        if(s%2)        {            printf("NO\n");            continue;        }        if(m>n)swap(m,n);//方便计算使a为大杯        int ans=bfs();        if(ans)printf("%d\n",ans);        else printf("NO\n");    }    return 0;}

另有大牛思路供参考:

设两个小瓶子容积分别为a,b,问题转化成通过两个小瓶子的若干次倒进或倒出操作得到(a+b)/2体积的可乐,设两个小瓶子被倒进或倒出x次和y次(这里的x和y是累加后的操作,即x=第一个瓶子倒出的次数-倒进的次数,y=第二个瓶子倒出的次数-倒进的次数),那么问题转化成: 
这里写图片描述 
所以|x+|y|的最小值为(c+d)/2,通过x和y的通解形式显然可以看出x和y一正一负,不妨设x<0,那么就是往第一个小瓶子倒进x次,第二个小瓶子倒出y次,但是由于瓶子容积有限,所以倒进倒出操作都是通过大瓶子来解决的,一次倒进操作后为了继续使用小瓶子还要将小瓶子中可乐倒回大瓶子中,倒出操作同理,所以总操作次数是(c+d)/2*2=c+d,但是注意最后剩下的(a+b)/2体积的可乐一定是放在两个小瓶子中较大的那个中,而不是再倒回到大瓶子中,所以操作数要减一,答案就是c+d-1 


#include<cstdio>#include<iostream>using namespace std;int gcd(int a,int b){    return b?gcd(b,a%b):a;}int main(){    int a,b,c;    while(scanf("%d%d%d",&a,&b,&c),a+b+c)    {        a/=gcd(b,c);        if(a&1)printf("NO\n");        else printf("%d\n",a-1);    }    return 0;}


0 0