hdoj 1495 (bfs())(非常可乐)
非常可乐
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8058 Accepted Submission(s): 3227
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 3 4 1 3 0 0 0
Sample Output
NO 3
My solution:
/*2015.11.6*/
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
int v[3],half;
bool map[103][103][103];//int map[103][103][103];也可以,不过比较占内存.bool类型一个元素只占一个字节
struct stu
{
int v[3];
int tep;
};
int match(stu b)
{
int i,j=0;
for(i=0;i<3;i++)
if(b.v[i]==half)
j++;
if(j==2)
return 1;
else
return 0;
}
int bfs()
{
int i,j,k,mark[3];
queue<stu>q;
stu temp,s;
s.v[0]=v[0];
s.v[1]=s.v[2]=0;
s.tep=0;
q.push(s);
while(!q.empty())
{
memset(mark,0,sizeof(mark));
temp=q.front();
q.pop();
for(i=0;i<3;i++)
{
if(temp.v[i])//从这个杯子倒出,因而不能再往这个杯子倒 ,所以用mark标记一下
{
mark[i]=1;
for(j=0;j<3;j++)
{
s=temp;
if(!mark[j])
{
if(temp.v[j]<v[j])
{
k=v[j]-temp.v[j];
if(temp.v[i]>=k)
{
s.v[j]=v[j];
s.v[i]-=k;
}
else
{
s.v[i]=0;
s.v[j]=temp.v[j]+temp.v[i];
}
if(!map[s.v[0]][s.v[1]][s.v[2]])
{
s.tep++;
if(match(s))//判断是否已经均分
return s.tep;
q.push(s);
map[s.v[0]][s.v[1]][s.v[2]]=1;
}
}
}
}
mark[i]=0;//此次操作完成后,取消标记
}
}
}
return 0;
}
int main()
{
int ans;
while(scanf("%d%d%d",&v[0],&v[1],&v[2])==3&&(v[0]||v[1]||v[2]))
{
memset(map,0,sizeof(map));
ans=0;
if(v[0]%2)//若可乐体积为奇数,则无法均分
printf("NO\n");
else
{
half=v[0]/2;
if(v[1]==half||v[2]==half)//若恰有容量为一半的杯子,则直接 输出步数为1
ans=1;
else
ans=bfs();
if(ans)
printf("%d\n",ans);
else
printf("NO\n");
}
}
return 0;
}