您的位置:首页 > 其它

搜索专题(BFS)HDU 1495-非常可乐

2016-12-01 20:29 309 查看
题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1495

思路分析:

因为涉及到求最少次数,所以第一感觉是用BFS模拟倒可乐,设得到三个杯子中可乐分别记为a,b,c,可以用一个mark数组查重,因为通过不同的方式得到相同的abc时,只要取步数最少的那种即可。结束条件的判断需要注意,一开始我以为只要使一个杯子中可乐为1/2S即可,后来发现要把另外两份倒在一起才算平分完。

这道题我最开始犯了一个错误,我以为a,b,c可以为小数,后来才发现题目说了要为整数,这样一来,如果可乐为奇数的话可以直接输出NO了。还是要看清楚题目对数据的限制条件才是啊。

后来百度这道题发现还可以用数论知识解决,(orz,我还没接触过数论的题)。

数论解法链接:http://blog.csdn.net/v5zsq/article/details/52097459

代码实现:

#include"cstdio"
#include"queue"
#include"map"
#include"cstring"
using namespace std;
int S,N,M;
int mark[105][105];
int aczc(int&p,int&q,int ma)
{
if(p==0||q==ma)
return 0;
if(p>=ma-q)
{
p=p-(ma-q);
q=ma;
}
else
{
q=p+q;
p=0;
}
return 1;
}
int BFS(int cnt,int x,int y,int z)
{
memset(mark,-1,sizeof(mark));
typedef pair<int,int>p;
typedef pair<p,p>P;
queue<P>que;
que.push(P(p(x,y),p(z,cnt)));
while(!que.empty())
{
int a,b,c;
x=que.front().first.first;
y=que.front().first.second;
z=que.front().second.first;
cnt=que.front().second.second;
que.pop();
//结束条件:两个杯子为S/2
if(x==S/2&&(y==0||z==0)||y==S/2&&(x==0||z==0)||z==S/2&&(x==0||y==0))
{
//printf("a%d b%d c%d cnt%d\n",x,y,z,cnt);
return cnt;
}
a=x;b=y;c=z;
if(aczc(a,b,N)&&mark[a][b]==-1)
{
que.push(P(p(a,b),p(c,cnt+1)));
mark[a][b]=c;
}
a=x;b=y;c=z;
if(aczc(a,c,M)&&mark[a][b]==-1)
{
que.push(P(p(a,b),p(c,cnt+1)));
mark[a][b]=c;
}
a=x;b=y;c=z;
if(aczc(b,a,S)&&mark[a][b]==-1)
{
que.push(P(p(a,b),p(c,cnt+1)));
mark[a][b]=c;
}
a=x;b=y;c=z;
if(aczc(b,c,M)&&mark[a][b]==-1)
{
que.push(P(p(a,b),p(c,cnt+1)));
mark[a][b]=c;
}
a=x;b=y;c=z;
if(aczc(c,a,S)&&mark[a][b]==-1)
{
que.push(P(p(a,b),p(c,cnt+1)));
mark[a][b]=c;
}
a=x;b=y;c=z;
if(aczc(c,b,N)&&mark[a][b]==-1)
{
que.push(P(p(a,b),p(c,cnt+1)));
mark[a][b]=c;
}
}
return 0;
}
int main()
{
while(1)
{
scanf("%d%d%d",&S,&N,&M);
if(S==0&&N==0&&M==0)
break;
if(S%2!=0)
{
printf("NO\n");
continue;
}
int x=BFS(0,S,0,0);
if(x)
printf("%d\n",x);
else printf("NO\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: