UVA10603 倒水问题BFS

本文介绍了一种使用类似Dijkstra算法的方法来解决水罐问题,通过寻找从初始状态到目标状态的最短路径,以求得将水罐中的水量调整到特定目标所需的最少倒水次数。代码中详细展示了如何利用优先队列和状态更新来实现这一过程。

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

使用类似dijkstra的方式求解  

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;

const int maxn=200+5;
int vis[maxn][maxn],cap[3],ans[maxn];//ans存储到达当前水量的最短路径
//vis是二维数组,因为知道前2个水杯的水量,第三个水杯即为确定的
struct Node{
    int v[3],dist;
    bool operator < (const Node & rhs) const{
        return dist > rhs.dist;
    } //变量dist表示达到当前状态需要取出的水量
};

void update_ans (const Node & u){
    for(int i=0;i<3;i++){
        int d=u.v[i];
        if(ans[d]<0||u.dist<ans[d]) ans[d]=u.dist; //剪枝
    }//每次更新ans把三个水杯各自水量的最短路径进行更新
}

void bfs (int dest){
    memset(vis,0,sizeof(vis));
    memset(ans,-1,sizeof(ans));
    priority_queue<Node> q;
    Node start;
    start.dist=0;
    start.v[0]=0;start.v[1]=0;start.v[2]=cap[2];
    q.push(start);
    vis[0][0]=1;            //初始第一和第二个水杯都是0
    while(!q.empty()){
        Node u=q.top();
        q.pop();
        update_ans(u);      //对当前已进入队列的结点更新状态
        if(ans[dest]>=0)break;
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++) if(i!=j){ //i是出水的水杯编号 j是入水的水杯
                if(u.v[i]==0 || u.v[j] == cap[j]) continue;
                int amount =min(cap[j],u.v[i]+u.v[j])-u.v[j];
                Node u2;
                memcpy(&u2,&u,sizeof(u));   //memcpy可对结构体对象使用
                u2.dist=u.dist+amount;
                u2.v[i] -= amount;
                u2.v[j] += amount;
                if(!vis[u2.v[0]][u2.v[1]]){ // 注意此处v数组的下标是0和1不是i和j
                    vis[u2.v[0]][u2.v[1]] = 1;
                    q.push(u2);
                }
        }
    }
    while(dest >= 0){
        if(ans[dest] >= 0){ //从目标水量d开始,查找距离d最近的d'
            printf("%d %d\n",ans[dest],dest);
            return ;
        }
        dest--;//无法找到当前dest的答案则dest--
    }
}

int main (){
    //freopen("datain.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        int d;
        scanf("%d%d%d%d",&cap[0],&cap[1],&cap[2],&d);
        //输入3个水杯的容量和目标水量,求到达该目标水量的最小倒水量
        bfs(d);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值