广搜-nyoj-隐式图的搜索-三个水杯

本文探讨了一个经典的三杯水问题,通过编程实现找到从初始状态达到目标状态所需的最少倒水次数。使用广度优先搜索算法,模拟不同情况下水在三个不同容量的杯子间转移的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

三个水杯

描述
给出三个水杯,大小不一,并且只有最大的水杯的水是装满的,其余两个为空杯子。三个水杯之间相互倒水,并且水杯没有标识,只能根据给出的水杯体积来计算。现在要求你写出一个程序,使其输出使初始状态到达目标状态的最少次数。
输入
第一行一个整数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

下面的图引用了别人的点击打开链接,三个水杯间的倒水情况:




一个杯子,要么被倒满,要么倒完。自己的代码写得特麻烦,别人的好简单!!!!

#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#include<cstdlib>
#include<cctype>
#include<cstring>
#include<cmath>
using namespace std;
int vis[101][101][101];//记录是否被访问
struct StateNode
{
    int cur[3];//记录水杯当前有多少水
    int v[3];//记录水杯大小
    int step;//步数
};
queue<StateNode> q;
int Sucess(StateNode a,StateNode b)
{
    //比较是否相等
    return (a.cur[0] == b.cur[0] && a.cur[1] == b.cur[1] && a.cur[2] == b.cur[2]);
}
int main()
{
    int t,res;
    StateNode b,e;      //e为需要的最终状态
    cin>>t;
    while(t--)
    {
        res=-1;
        while(!q.empty()) //清空队列
        {
            q.pop();
        }
        cin>>b.v[0]>>b.v[1]>>b.v[2];
        //下面开始模拟倒水,并搜索
        b.cur[0]=b.v[0];//首先先给最大的水杯倒满水
        b.cur[1]=b.cur[2]=0;//小杯子为0
        b.step=0;//记录步数

        cin>>e.cur[0]>>e.cur[1]>>e.cur[2];

        int ok=0;//记录是否可以到达结尾状态
        memset(vis,0,sizeof(vis));
        q.push(b);//加入队列
        vis[b.cur[0]][b.cur[1]][b.cur[2]]=1;//已经在访问或者已经访问
        while(!q.empty()) //进行广搜
        {
            StateNode u=q.front();
            //cout<<u.cur[0]<<" "<<u.cur[1]<<" "<<u.cur[2]<<endl;
            q.pop();
            if(Sucess(u,e)) //成功并结束
            {
                res=u.step;
                break;
            }
            //else 模拟倒水
            for(int i=0; i<=2; i++) //用每一个被子给其他两个被子倒水
            {
                for(int j=0; j<=2; j++)
                {
                    if(i!=j)
                    {
                        int minv=u.v[j]-u.cur[j];//从当前状态到被子倒满,需要的水
                        if(u.cur[i]<minv) //当前的水小于需要的水,则能用的水变为当前的水
                        {
                            minv=u.cur[i];
                        }
                        //出现新节点
                        StateNode v=u;
                        v.cur[i]-=minv;//必须先减去
                        v.cur[j]+=minv;
                        v.step=u.step+1;//更新步数
                        //cout<<u.step<<endl;
                        if(!vis[v.cur[0]][v.cur[1]][v.cur[2]]) //该结点没有被访问
                        {
                            q.push(v);//加入队列
                            vis[v.cur[0]][v.cur[1]][v.cur[2]]=1;//已访问
                        }
                    }
                }
            }

        }
        cout<<res<<endl;
    }
    return 0;
}

以下是超长代码

 
#include<stdio.h>
#include<string.h>
#include<queue>
#include<math.h>
using namespace std;
int v1,v2,v3,e1,e2,e3,cnt,Max,flag;
struct node
{
    int a,b,c,step;
    bool operator <(const node &d)const
    {
        return d.step<step;
    }

};
priority_queue<node> pq;
int vis[105][105][105];
void bfs()
{
    int i;
    while(!pq.empty())
    {
        node t,t1;
        t=pq.top();
        pq.pop();
        //getchar();
        if(t.a==e1&&t.b==e2&&t.c==e3)
        {
            printf("%d\n",t.step);
            return ;
        }
        if(t.a-(v2-t.b)>=0)
        {
            if(!vis[t.a-(v2-t.b)][v2][t.c])       //A把B装满
            {
                t1.a=t.a-(v2-t.b);
                t1.b=v2;
                t1.c=t.c;
                vis[t.a-(v2-t.b)][v2][t.c]=1;
                t1.step=t.step+1;
                pq.push(t1);
               // printf("%d %d %d %d\n",t1.a,t1.b,t1.c,t1.step);
            }
        }

        else if(!vis[0][t.b+t.a][t.c]&&t.b+t.a<=v2)       //把A倒完给B
        {
            t1.a=0;
            t1.b=t.b+t.a;
            t1.c=t.c;
            vis[0][t.b+t.a][t.c]=1;
            t1.step=t.step+1;
            pq.push(t1);
            //printf("%d %d %d %d\n",t1.a,t1.b,t1.c,t1.step);
        }
        if(t.a-(v3-t.c)>=0)
        {
            if(!vis[t.a-(v3-t.c)][t.b][v3])     //A把C倒满
            {
                t1.a=t.a-(v3-t.c);
                t1.b=t.b;
                t1.c=v3;
                vis[t.a-(v3-t.c)][t.b][v3]=1;
                t1.step=t.step+1;
                pq.push(t1);
               // printf("%d %d %d %d\n",t1.a,t1.b,t1.c,t1.step);
            }
        }
        else if(!vis[0][t.b][t.a+t.c]&&t.a+t.c<=v3)     //把A倒完给C
        {
            t1.a=0;
            t1.b=t.b;
            t1.c=t.a+t.c;
            vis[0][t.b][t.a+t.c]=1;
            t1.step=t.step+1;
            pq.push(t1);
            //printf("%d %d %d %d\n",t1.a,t1.b,t1.c,t1.step);
        }
        if(t.b-(v1-t.a)>=0)
        {
            if(!vis[v1][t.b-(v1-t.a)][t.c])    //B把A倒满
            {
                t1.a=v1;
                t1.b=t.b-(v1-t.a);
                t1.c=t.c;
                vis[v1][t.b-(v1-t.a)][t.c]=1;
                t1.step=t.step+1;
                pq.push(t1);
               // printf("%d %d %d %d\n",t1.a,t1.b,t1.c,t1.step);
            }
        }
        else if(!vis[t.a+t.b][0][t.c]&&t.a+t.b<=v1)     //把B倒完给A
        {
            t1.a=t.a+t.b;
            t1.b=0;
            t1.c=t.c;
            vis[t.a+t.b][0][t.c]=1;
            t1.step=t.step+1;
            pq.push(t1);
            //printf("%d %d %d %d\n",t1.a,t1.b,t1.c,t1.step);
        }
        if(t.b-(v3-t.c)>=0)
        {
            if(!vis[t.a][t.b-(v3-t.c)][v3])    //B把C倒满
            {
                t1.a=t.a;
                t1.b=t.b-(v3-t.c);
                t1.c=v3;
                vis[t.a][t.b-(v3-t.c)][v3]=1;
                t1.step=t.step+1;
                pq.push(t1);
              //  printf("%d %d %d %d\n",t1.a,t1.b,t1.c,t1.step);
            }
        }

        else if(!vis[t.a][0][t.c+t.b]&&t.c+t.b<=v3)     //把B倒完给C
        {
            t1.a=t.a;
            t1.b=0;
            t1.c=t.c+t.b;
            vis[t.a][0][t.c+t.b]=1;
            t1.step=t.step+1;
            pq.push(t1);
            //printf("%d %d %d %d\n",t1.a,t1.b,t1.c,t1.step);
        }
        if(t.c-(v1-t.a)>=0)
        {
            if(!vis[v1][t.b][t.c-(v1-t.a)])    //C把A倒满
            {
                t1.a=v1;
                t1.b=t.b;
                t1.c=t.c-(v1-t.a);
                vis[v1][t.b][t.c-(v1-t.a)]=1;
                t1.step=t.step+1;
                pq.push(t1);
               // printf("%d %d %d %d\n",t1.a,t1.b,t1.c,t1.step);
            }
        }

        else if(!vis[t.a+t.c][t.b][0]&&t.c+t.a<=v1)     //把C倒完给A
        {
            t1.a=t.a+t.c;
            t1.b=t.b;
            t1.c=0;
            vis[t.a+t.c][0][0]=1;
            t1.step=t.step+1;
            pq.push(t1);
           // printf("%d %d %d %d\n",t1.a,t1.b,t1.c,t1.step);
        }
        if(t.c-(v2-t.b)>=0)
        {
            if(!vis[t.a][v2][t.c-(v2-t.b)])    //C把B倒满
            {
                t1.a=t.a;
                t1.b=v2;
                t1.c=t.c-(v2-t.b);
                vis[t.a][v2][t.c-(v2-t.b)]=1;
                t1.step=t.step+1;
                pq.push(t1);
              //  printf("%d %d %d %d\n",t1.a,t1.b,t1.c,t1.step);
            }
        }

        else if(!vis[t.a][t.b+t.c][0]&&t.c+t.b<=v2)     //把C倒完给B
        {
            t1.a=t.a;
            t1.b=t.b+t.c;
            t1.c=0;
            vis[t.a][t.b+t.c][0]=1;
            t1.step=t.step+1;
            pq.push(t1);
           // printf("%d %d %d %d\n",t1.a,t1.b,t1.c,t1.step);
        }
    }
    flag=1;
}
int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        memset(vis,0,sizeof(vis));
        flag=0;
        while(!pq.empty())
            pq.pop();
        node ss;
        scanf("%d%d%d%d%d%d",&v1,&v2,&v3,&e1,&e2,&e3);
        ss.step=0;
        ss.a=v1;
        ss.b=0;
        ss.c=0;
        vis[ss.a][0][0]=1;
        pq.push(ss);
        bfs();
        if(flag==1)
            printf("-1\n");
    }
    return 0;
}
        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值