zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    LeetCode 242. Valid Anagram (验证变位词)
    LeetCode 205. Isomorphic Strings (同构字符串)
    LeetCode 204. Count Primes (质数的个数)
    LeetCode 202. Happy Number (快乐数字)
    LeetCode 170. Two Sum III
    LeetCode 136. Single Number (落单的数)
    LeetCode 697. Degree of an Array (数组的度)
    LeetCode 695. Max Area of Island (岛的最大区域)
    Spark中的键值对操作
    各种排序算法总结
  • 原文地址:https://www.cnblogs.com/sykline/p/10311292.html
Copyright © 2011-2022 走看看