UVA 10603_Fill

题意:

给定三个杯子容量,初始只有第三个杯子满,其余为空,求最少需要倒多少水才能让某一杯子中有d升水,如果不能达到,则小于d且尽量接近。

分析:

因为要求转移水量最少,所以采用优先级队列保存每次的状态,保证每次都是取出转移水量最少的点进行扩展。bfs求出杯中水达到d(接近d)时最少转移水量。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
const int maxn=205, INF=0x3fffffff;
struct Node{
    int n[3];
    int dist;
    bool operator < (const Node& a) const{
        return dist > a.dist;
    }
};
int vis[maxn][maxn], v[3], ans[maxn], d;
void bfs()
{
    memset(vis, 0, sizeof(vis));
    memset(ans, -1, sizeof(ans));
    priority_queue<Node>q;
    Node s;
    s.n[0]=0, s.n[1] = 0, s.n[2] = v[2];
    s.dist = 0;
    vis[0][0]=1;
    q.push(s);
    while(!q.empty()){
        Node t = q.top(); q.pop();
        for(int i = 0; i < 3; i++){
            if(ans[t.n[i]]<0) ans[t.n[i]] = t.dist;
            else   ans[t.n[i]] = min(ans[t.n[i]], t.dist);
        }
        if(ans[d]>=0) break;
        for(int i = 0; i < 3; i++){//i->j
            for(int j = 0; j < 3; j++){
                if(i!=j){
                    if(t.n[i]==0||t.n[j]==v[j]) continue;
                    int t1 = t.n[i], t2 = t.n[j];
                    int temp = min(t1, v[j] - t2);
                    Node nt;
                    nt.n[i] = t1 - temp;
                    nt.n[j] = t2 + temp;
                    nt.n[3-i-j] = t.n[3-i-j];
                    nt.dist = t.dist + temp;
                    if(!vis[nt.n[0]][nt.n[1]]){//总水量一定,前两个杯子水量确定,第三个杯子水量也确定了
                        vis[nt.n[0]][nt.n[1]] = 1;
                        q.push(nt);
                    }
                }
            }
        }
    }
    while(ans[d]<0) d--;
    printf("%d %d
",ans[d], d);
    return;
}

int main (void)
{
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d%d%d",&v[0],&v[1],&v[2],&d);
        bfs();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Tuesdayzz/p/5758839.html