NYOJ-21 三个水杯

三个水杯

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 4
描述
给出三个水杯,大小不一,并且只有最大的水杯的水是装满的,其余两个为空杯子。三个水杯之间相互倒水,并且水杯没有标识,只能根据给出的水杯体积来计算。现在要求你写出一个程序,使其输出使初始状态到达目标状态的最少次数。
输入
第一行一个整数N(0<N<50)表示N组测试数据
接下来每组测试数据有两行,第一行给出三个整数V1 V2 V3 (V1>V2>V3 V1<100 V3>0)表示三个水杯的体积。
第二行给出三个整数E1 E2 E3 (体积小于等于相应水杯体积)表示我们需要的最终状态
输出
每行输出相应测试数据最少的倒水次数。如果达不到目标状态输出-1
样例输入
2
6 3 1
4 1 1
9 3 2
7 1 1
样例输出
3

-1

【解析】

看到这个题的时候,其实没什么想法就是觉得需要不断的需要一个杯子去满足另个杯子这样是有循环的,看了大佬的算法之后发现这个其实可以构建一个 解空间,再用广度搜索,搜索下去。直到找到答案,其实大概是这么个过程,比如你6,3,1这是水杯的容积,4,1,1是你需要满足的,刚开始就第一个杯子是满的,我们列出所有的可能再去选择,6,3,1可以变成3,3,0或5,0,1这样的话之后可以变成3,2,1或者2,3,1或者4,1,1,那么显然4,1,1是我们需要的答案,其实我们是没有量度的所以只能通过一个杯子给另一个杯子,而且肯定要装满,不然的话你根本不知道自己的杯子里的水有多少。用队列把每一种可能都列出来。其实这有个过程你遇到有杯子如果可以倒你就只能把那个杯子倒满你控制不了你要倒多少因为你不知道体积。所以有if的那两个条件,如果你两个杯子加起来的水比后一个杯子容积小那就把那个杯子给装满。这是一种情况,如果两个杯子装起来的容积比下一个杯子的容积大,那么也是一样的把那个杯子装满,然后前一个杯子的容积相减,这样下去其实就是不断的装,列举出所有的情况,因为要靠A去装满B也需要把C全部倒满,然后C再倒给B。这样不断的凑,把这样的过程集合起来来搜索。还有就是记录过程的时候需要把步骤记录下来。

#include<iostream>
#include<cstdio>
#include<string.h>
#include<queue>
using namespace std;
struct Water
{
    int water1[3];
    int step;
}pos1,pos2;
int a[3];
int enof[3];
int f[300][300];
void bfs()
{
    queue<Water> q;
    memset(f,0,sizeof(f));
    pos1.water1[0]=a[0];
    pos1.water1[1]=pos1.water1[2]=pos1.step=0;
    q.push(pos1);
    f[a[0]][0]=1;
    while(!q.empty())
    {
        int i,j;
        pos1=q.front();
        q.pop();
        for(int i=0;i<3&&pos1.water1[i]>=0;i++)
        for(int j=0;j<3;j++)
        {
            if(i!=j)
            {
                pos2=pos1;
                if(pos1.water1[0]==enof[0]&&pos1.water1[1]==enof[1])
                {
                    printf("%d\n",pos1.step);
                    return;
                }
                if(pos1.water1[i]+pos1.water1[j]<=a[j])
                {
                    pos2.water1[i]=0;//第一种情况
                    pos2.water1[j]=pos1.water1[i]+pos1.water1[j];
                }
                else
                {
                    pos2.water1[i]=pos1.water1[i]+pos1.water1[j]-a[j];
                    pos2.water1[j]=a[j];//第二种情况
                }
                if(!f[pos2.water1[0]][pos2.water1[1]])
                {
                    pos2.step=pos1.step+1;
                    if(pos2.water1[0]==enof[0]&&pos2.water1[1]==enof[1])
                    {
                        printf("%d\n",pos2.step);
                        return ;
                    }
                    f[pos2.water1[0]][pos2.water1[1]]=1;
                    q.push(pos2);
                }
        }
    }
    }
    printf("-1\n");
}
int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        for(int i=0;i<3;i++)
            scanf("%d",&a[i]);
        for(int i=0;i<3;i++)
            scanf("%d",&enof[i]);
        bfs();
    }
    return 0;
}
这样才能凑出B就是一个循环倒水的问题。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值