zoukankan      html  css  js  c++  java
  • 隐式图的遍历

    好久不看都快忘了...

    一些奇怪的问题可以归为隐式图的遍历

    NEUOJ544

    Problem Description
     
    there is an old saying,"You can not do anything without water"or"Water is the source of life". Besides, human beings are made of water. 
    Sister Wang thinks that woman is made of water, so she drinks a lot of water every day. One day, she drinks too much, and can only drink k litre(s) now, but she just has three cups with no scale, which can contain a, b, c litre(s) of water respectively. Each cup can only be filled full with water or be empty. They can be poured from the one to the other one. Since she is too lazy to pour k litre(s). She just want to know how many times at least to pour k litre(s) with these three cups. Yeah, it is just like the problem as you meet when you are in the primary school. Sister Wang want to get the result that there is one cup contains k litre(s).
    At the beginning, each cup can be full or empty. Getting full or pouring empty of each cup does not count the times, only count the times when pouring from each other.
     
    Input
    There are multiple test cases, the number of cases T (1 ≤ T ≤ 20) will be given in the first line of input data. Each test case will include four integer a,b,c and k (1 ≤ k < a,b,c ≤ 100).
     
    Output

    For each test case, output the least times of pouring.

    If you can not get k litre(s),please output -1.

    Sample Input
    1 12 7 3 2
    Sample Output
    2
     
    三个杯子中的水a,b,c可以看成一个状态,用一个queue维护这个状态的转移。
    比较迷惑的地方就是可以不计次数地补满或者倒空杯子
    对于一个从queue中取出的状态a,b,c,我用了个三重循环枚举了所有免费转移到的状态,分别对每个免费转移到的状态尝试插入queue
    由于要多次尝试插入就把尝试插入单独写了个函数
     
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    const int maxn = 107, INF = 100000000;
    int vol[3], vis[maxn][maxn][maxn], mintimes;//vol容量
    struct state{
        int cup[3], times;
        state(){}
        state(int a, int b, int c, int t){
            cup[0] = a;
            cup[1] = b;
            cup[2] = c;
            times = t;
        }
    };
    queue<state> Q;
    void daoshui(state u){
        for(int i = 0; i < 3; i++)
            for(int j = 0; j < 3; j++)//从i杯往j杯倒水,共3*3种方案
                if(i != j){//排除自己给自己倒
                    if(u.cup[i] == 0 || u.cup[j] == vol[j])//i满或者j空 跳过
                        continue;
                    int amount = min(vol[j], u.cup[i]+u.cup[j]) - u.cup[j];//amount是转移的水量 1.i杯可以将j杯装满并且还有剩余 2.i杯全部倒入j杯,j杯仍没满
                    state u2(u);
                    u2.cup[i] -= amount;
                    u2.cup[j] += amount;
                    u2.times++;//u2是转移后的新状态
                    if(!vis[u2.cup[0]][u2.cup[1]][u2.cup[2]]){//尝试入队
                        vis[u2.cup[0]][u2.cup[1]][u2.cup[2]] = 1;
                        Q.push(u2);
                    }
                }
    }
    
    void bfs(int k){
        state st(0, 0, 0, 0);//反正可以不计次数地倒满清空
        vis[0][0][0] = 1;//不是无脑插入,每次取出时检查是否重复,那样入队出队太多了;而是在插入的地方检查重复
        Q.push(st);
        while(!Q.empty()){
            state u = Q.front();
            Q.pop();
            for(int i = 0; i < 3; i++)
            if(u.cup[i] == k){
                if(u.times < mintimes)
                    mintimes = u.times;
                return;
            }//终止条件写在最前面嗯很奇妙
           int arr[3];
           for(int l = 0; l < 3; l++)//1杯
           {
               if(l == 0)
                    arr[0] = 0;//
               else if (l == 1)
                    arr[0] = vol[0];//
               else
                    arr[0] = u.cup[0];//不变
               for(int i = 0; i < 3; i++){//2杯
                    if(i == 0)
                        arr[1] = 0;
                    else if(i == 1)
                        arr[1] = vol[1];
                    else
                        arr[1] = u.cup[1];
    
                    for(int j = 0; j < 3; j++){//3杯
                        if(j == 0){
                            arr[2] = 0;
                        }
                        else if(j == 1){
                            arr[2] = vol[2];
                        }
                        else
                            arr[2] = u.cup[2];
                        daoshui(state(arr[0], arr[1], arr[2], u.times));
                    }
               }
           }
        }
    }
    int main(){
        //freopen("in.txt", "r", stdin);
        int t;
        scanf("%d", &t);
        while(t--){
            while(!Q.empty())
                Q.pop();
            int k;
            scanf("%d%d%d%d", &vol[0], &vol[1], &vol[2], &k);
            mintimes = INF;
            memset(vis, 0, sizeof(vis));
            bfs(k);
            if(mintimes < INF)
                printf("%d
    ", mintimes);
            else
                printf("-1
    ");
        }
        return 0;
    }

    以后忘了就来看

     
    搞图论是没有用的,转行做数学题了hh
  • 相关阅读:
    读《奇点临近》
    C++中rand()函数的用法
    第四届蓝桥杯 c/c++真题
    ACM做题过程中的一些小技巧
    树状数组
    go单元测试进阶篇
    浓缩的才是精华:浅析GIF格式图片的存储和压缩
    腾讯IVWEB团队:WebRTC 点对点直播
    Mongodb Geo2d索引原理
    Unity编译Android的原理解析和apk打包分析
  • 原文地址:https://www.cnblogs.com/DearDongchen/p/7203542.html
Copyright © 2011-2022 走看看