传送门:[](http://acm.hdu.edu.cn/showproblem.php?pid=1495hdu 1495 非常可乐)
题目是中文的没有什么理解问题
解题思路
先来把问题特殊化,假如我们有三个容器分别容量是6升,3升还有一升,现在我们把六升的容器装满水,问经过多少次之后能到达给的4升。这个我们很容易通过简单地思考就能知道答案,过程为:
(6,0,0)->(3,3,0)->(3,2,1)->(4,3,0);
然后我们要解决的问题就变为了:有三个容器大中小三种类型,在最开始的时候只有最大的杯子装满了水,经过n次倒水之后将其中一个容器中的水变为给定d升。
由于我们要找的是最小的步骤,那么可以用BFS,来找出最小的步骤。
那么问题来了,应该怎么进行枚举呢?
因为其中两个杯子确定了那么第三个杯子的剩余量就确定了,我们只需要记录其中的两个杯子的状态就可以了,我们通过vis[i][j]
这个数组中,i表示中等容量的容器现有水量,j表示最小容量的容器的现有水量。
然后我们只需要遍历某个容器向另一个容器倒水就可以了。这一共六种状态。用两个for循环就能解决的。倒水过程代码如下:
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
if(i == j) //不能自己向自己倒水
continue;
//下面想不通可举个数据自己尝试一下,cur.v[i]表示第i个杯子的水的剩余量
//cup_capacity[j]-cur.v[j]表示第j个杯子可以接收的最大水量,
//倒水之后必须是两种状态中的其中一种,第i个杯子剩余的水为空
//第j个杯子水中满了,但是第i个杯子不一定为空
int amount = min(cur.v[i],cup_capacity[j]-cur.v[j]); // 取出可以倒向第j个杯子的水
for(int k=0;k<3;k++)
next.v[k] = cur.v[k];
//第i个杯子倒向第j个杯子
next.v[i] = cur.v[i] - amount;
next.v[j] = cur.v[j] + amount;
//如果这个状态没有被访问过,就把这个状态压入队列
if(!vis[next.v[1]][next.v[2]])
{
vis[next.v[1]][next.v[2]] = true;
next.deepth = cur.deepth + 1;
q.push(next);
}
}
}
对应于这个题目来讲,因为S = M + N所以M或者N中必然会有一个数会大于S/2;随后如果要平分的话肯定要max(M,N)中的水量等于S这个容器中的水量并且等于S/2;
这样就抽象为了上面的倒水问题:
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
int cup_capacity[4];
bool vis[105][105];
struct Node{
int v[3];
int deepth;
};
int bfs()
{
if(cup_capacity[0]%2)
return -1;
queue<Node>q;
Node cur;
Node next;
cur.v[0] = cup_capacity[0];
cur.v[1] = 0;
cur.v[2] = 0;
cur.deepth = 0;
vis[0][0] = true;
q.push(cur);
while(!q.empty())
{
cur = q.front();
q.pop();
if(cur.v[0] == cur.v[1] && cur.v[2] == 0)
return cur.deepth;
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
if(i == j) //不能自己向自己倒水
continue;
//下面想不通可举个数据自己尝试一下,cur.v[i]表示第i个杯子的水的剩余量
//cup_capacity[j]-cur.v[j]表示第j个杯子可以接收的最大水量,
//倒水之后必须是两种状态中的其中一种,第i个杯子剩余的水为空
//第j个杯子水中满了,但是第i个杯子不一定为空
int amount = min(cur.v[i],cup_capacity[j]-cur.v[j]); // 取出可以倒向第j个杯子的水
for(int k=0;k<3;k++)
next.v[k] = cur.v[k];
//第i个杯子倒向第j个杯子
next.v[i] = cur.v[i] - amount;
next.v[j] = cur.v[j] + amount;
//如果这个状态没有被访问过,就把这个状态压入队列
if(!vis[next.v[1]][next.v[2]])
{
vis[next.v[1]][next.v[2]] = true;
next.deepth = cur.deepth + 1;
q.push(next);
}
}
}
}
return -1;
}
int main()
{
while(scanf("%d%d%d",&cup_capacity[0],&cup_capacity[1],&cup_capacity[2])!=EOF)
{
memset(vis,false,sizeof vis);
if(!cup_capacity[0] && !cup_capacity[1] && !cup_capacity[2])
break;
int tmp1 = cup_capacity[1];
int tmp2 = cup_capacity[2];
cup_capacity[1] = max(tmp1,tmp2);
cup_capacity[2] = min(tmp1,tmp2);
/*if(cup_capacity[0]%2)
printf("NO\n");
else if(cup_capacity[1] == cup_capacity[2])
printf("1\n");
else
printf("3\n");*/
int ans = bfs();
if(ans == -1)
printf("NO\n");
else
printf("%d\n",ans);
}
return 0;
}