• UVA


    题目:

    给出三个杯子(没有刻度线)的容量,起初之后第三个杯子是满的,其他的两个杯子是空的,容量分别是a、b、c。问最少需要倒多少升水才能让某一个杯子中的水有d升?如果不能恰好做到d升,就让某一个杯子里的水是D升,其中D<d并且尽量接近d。(1≤a,b,c,d≤200)。要求输出最少的倒水量和目标水量d或D。

    思路:

    菜是原罪,需要赎罪啊!!

    1.一看到这种求最小值的问题很应该想到是用BFS了。

    2.BFS需要标记状态呀,那201*201*201=8120601这内存有些吃不消啊,那前两个杯子的水固定了,总的水量又是不变的,那只用前两个杯子的

    水量就可以标记所有可能的状态了。这样就把状态缩小到201*201了。

    3.Node结构体中保存的是一个状态,“状态”这个词很玄乎啊,有到当前状态已经倒过的水量dist和三个杯子中还有的水量v[0]、v[1]、v[2]。

    4.紫书的代码写的优美啊!!值的好好的学习!!

    代码:

    #include <bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define MAX 1000000009
    #define FRE() freopen("in.txt","r",stdin)
    #define FRO() freopen("out.txt","w",stdout)
    using namespace std;
    typedef long long ll;
    const int maxn = 205;
    struct Node{
        int v[3],dist;//dist保存的是到当前状态已经倒过的最小水量
        bool operator<(const Node& rhs)const{
            return dist>rhs.dist;
        }
    };
    int vis[maxn][maxn],cap[3],ans[maxn];
    
    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;
        }
    }
    
    void solve(int a,int b,int c,int d){
        cap[0]=a;cap[1]=b;cap[2]=c;//记录目标状态的水量是多少
        memset(vis,0,sizeof(vis));//清空所有的可能出现的状态
        memset(ans,-1,sizeof(ans));//清空答案数组
        priority_queue<Node>q;
    
        Node start;//初始状态,按照题目要求赋值
        start.dist = 0;
        start.v[0] = start.v[1] = 0;
        start.v[2] = c;
        q.push(start);
        vis[0][0] = 1;//标记a、b杯子为空的状态
        while(!q.empty()){
            Node u = q.top();q.pop();
            update_ans(u);
            if(ans[d]>=0) break;//如果已经找到的答案就break
            for(int i=0; i<3; i++){//i表示的是倒出水的杯子
                for(int j=0; j<3; j++){//j表示的是被倒出水的杯子
                    if(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];//重点了!!
                        /*
                            要倒一定是全部倒出来,所以j杯子被倒水之后有两种状态
                            1.倒之后满了
                            2.倒之后没有满
                            从这两种状态中取一个最小的水量记录下来
                        */
                        Node u2;//赋值一个新的状态
                        memcpy(&u2, &u, sizeof(u));
                        u2.dist = u.dist+amount;
                        u2.v[i] -= amount;
                        u2.v[j] += amount;
                        if(!vis[u2.v[0]][u2.v[1]]){//如果这个状态没有出现过,就标记一下入队列
                            vis[u2.v[0]][u2.v[1]] = 1;
                            q.push(u2);
                        }
                    }
                }
            }
        }
        while(d>=0){//遍历答案并输出
            if(ans[d] >= 0){
                printf("%d %d
    ",ans[d],d);
                return;
            }
            d--;
        }
    }
    
    int main(){
        int T,a,b,c,d;
        scanf("%d",&T);
        while(T--){
            scanf("%d%d%d%d",&a,&b,&c,&d);
            solve(a,b,c,d);
        }
        return 0;
    }
  • 相关阅读:
    POJ 3683 Priest John&#39;s Busiest Day (2-SAT+输出可行解)
    Codeforces #2B The least round way(DP)
    避免死锁的银行家算法C++程序实现
    源代码编译安装MySQL5.6.12具体过程
    Android 设计模式
    Java与设计模式-适配器模式
    Java和Flex整合报错(五)
    三层架构—再思考
    怎样让DBGrid在按住Shift点鼠标的同时能将连续范围的多行选中?
    找出你的短板
  • 原文地址:https://www.cnblogs.com/sykline/p/10311292.html
Copyright © 2020-2023  润新知