zoukankan      html  css  js  c++  java
  • HDU1495 非常可乐 —— BFS + 模拟

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1495


    非常可乐

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 16814    Accepted Submission(s): 6805

    Problem Description
    大家一定觉的运动以后喝可乐是一件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou一起分享这一瓶可乐,而且一定要喝的和seeyou一样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升 (正好装满一瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。
     
    Input
    三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。
     
    Output
    如果能平分的话请输出最少要倒的次数,否则输出"NO"。
     
    Sample Input
    7 4 3 4 1 3 0 0 0
     
    Sample Output
    NO 3
     
    Author
    seeyou
     
    Source




    题解:

    1.由于每个容器不超过100, 所以枚举所有状态(1e6)也不会超时。所以直接用BFS。

    2.判重:

    2.1:其中S<=100,  1<=N<100, 1<=M<100,所以可以将当前三个容器的可乐量压缩成一个int类型,且最大不超过1009999(S放在前面,如果放在中间或者后面,就要加多一位了,这里有讲究),然后就可以开个vis[]数组直接检查状态status是否已经访问过了。

    2.2:其实不用把三个容器压缩成一个int类型,可以直接开个三维数组vis[110][110][110],每一维对应一个容器,也是1e6级别的大小,而且更加方便灵活。

    2.3:其实开二维数组就够了,因为总的可乐量是确定的,当其中两个容器的可乐量确定了,那剩下的容器的可乐量也就确定了。这一个简单的优化又把内存消耗降低了100倍。


    关于判重,目前自己有三个习惯的方法:STL的set、vis多维判重 与 vis status(int类型的以为判重)  。

    1. set判重,适用状态高度离散的判重(开数组不能满足其范围), 特点慢,能用数组判重就尽量不要用set判重。

    2.vis多维判重, 适用于状态集中且维度较少的情况。

    3.staus判重,适用于状态集中且维度较多的情况, 其本质就是把所有维度的状态都压缩成一个int类型, 所以status本质是一个哈希值。



    2.1(status判重):

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <vector>
     7 #include <queue>
     8 #include <stack>
     9 #include <map>
    10 #include <string>
    11 #include <set>
    12 #define ms(a,b) memset((a),(b),sizeof((a)))
    13 using namespace std;
    14 typedef long long LL;
    15 const int INF = 2e9;
    16 const LL LNF = 9e18;
    17 const int MOD = 1e9+7;
    18 const int MAXN = 2e6+10;
    19 
    20 //0为容器S, 1为容器N, 2为容器M
    21 struct node
    22 {
    23     int status, con[3], step;   //con[i]为容器i当前盛的可乐体积
    24 };
    25 int vol[3], vis[MAXN];  //vol[i]为容器i的容量
    26 
    27 queue<node>que;
    28 int bfs()
    29 {
    30     ms(vis,0);
    31     while(!que.empty()) que.pop();
    32 
    33     node now, tmp;
    34     now.con[0] = vol[0];    //初始状态只用容器S盛有可乐
    35     now.con[1] = now.con[2] = 0;
    36     now.status = vol[0]*10000;  //初始的状态
    37     now.step = 0;
    38     vis[now.status] = 1;
    39     que.push(now);
    40 
    41     while(!que.empty())
    42     {
    43         now = que.front();
    44         que.pop();
    45 
    46 //        cout<< now.status <<endl;
    47         if((now.con[0]==vol[0]/2 && now.con[1]==vol[0]/2)
    48            || (now.con[0]==vol[0]/2 && now.con[2]==vol[0]/2)
    49            || (now.con[1]==vol[0]/2 && now.con[2]==vol[0]/2))
    50                 return now.step;
    51 
    52         for(int i = 0; i<3; i++)    //模拟倒水的过程, i为倒, j为被倒
    53         for(int j = 0; j<3; j++)
    54         {
    55             if(i==j) continue;
    56             tmp = now;
    57             int pour = min(tmp.con[i], vol[j]-tmp.con[j]);  //能倒多少水
    58             tmp.con[j] += pour;
    59             tmp.con[i] -= pour;
    60             tmp.status = tmp.con[0]*10000+tmp.con[1]*100+tmp.con[2];    //更新状态
    61             if(!vis[tmp.status])
    62             {
    63                 vis[tmp.status] = 1;
    64                 tmp.step++;
    65                 que.push(tmp);
    66             }
    67         }
    68     }
    69     return -1;
    70 }
    71 
    72 int main()
    73 {
    74     while(scanf("%d%d%d",&vol[0], &vol[1], &vol[2]) && (vol[0]||vol[1]||vol[2]))
    75     {
    76         if(vol[0]%2)    //奇数肯定不能平分
    77         {
    78             printf("NO
    ");
    79             continue;
    80         }
    81         int ans = bfs();
    82         if(ans==-1)
    83             printf("NO
    ");
    84         else
    85             printf("%d
    ", ans);
    86     }
    87     return 0;
    88 }
    View Code

    2.2(三维判重):

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <vector>
     7 #include <queue>
     8 #include <stack>
     9 #include <map>
    10 #include <string>
    11 #include <set>
    12 #define ms(a,b) memset((a),(b),sizeof((a)))
    13 using namespace std;
    14 typedef long long LL;
    15 const int INF = 2e9;
    16 const LL LNF = 9e18;
    17 const int MOD = 1e9+7;
    18 const int MAXN = 100+10;
    19 
    20 struct node
    21 {
    22     int con[3], step;
    23 };
    24 int vol[3], vis[MAXN][MAXN][MAXN];
    25 
    26 queue<node>que;
    27 int bfs()
    28 {
    29     ms(vis,0);
    30     while(!que.empty()) que.pop();
    31 
    32     node now, tmp;
    33     now.con[0] = vol[0];
    34     now.con[1] = now.con[2] = 0;
    35     now.step = 0;
    36     vis[now.con[0]][now.con[1]][now.con[2]] = 1;
    37     que.push(now);
    38 
    39     while(!que.empty())
    40     {
    41         now = que.front();
    42         que.pop();
    43 
    44         if((now.con[0]==vol[0]/2 && now.con[1]==vol[0]/2)
    45            || (now.con[0]==vol[0]/2 && now.con[2]==vol[0]/2)
    46            || (now.con[1]==vol[0]/2 && now.con[2]==vol[0]/2))
    47                 return now.step;
    48 
    49         for(int i = 0; i<3; i++)    //模拟倒水的过程
    50         for(int j = 0; j<3; j++)
    51         {
    52             if(i==j) continue;
    53             tmp = now;
    54             int pour = min(tmp.con[i], vol[j]-tmp.con[j]);
    55             tmp.con[j] += pour;
    56             tmp.con[i] -= pour;
    57             if(!vis[tmp.con[0]][tmp.con[1]][tmp.con[2]])
    58             {
    59                 vis[tmp.con[0]][tmp.con[1]][tmp.con[2]] = 1;
    60                 tmp.step++;
    61                 que.push(tmp);
    62             }
    63         }
    64     }
    65     return -1;
    66 }
    67 
    68 int main()
    69 {
    70     while(scanf("%d%d%d",&vol[0], &vol[1], &vol[2]) && (vol[0]||vol[1]||vol[2]))
    71     {
    72         if(vol[0]%2)
    73         {
    74             printf("NO
    ");
    75             continue;
    76         }
    77         int ans = bfs();
    78         if(ans==-1)
    79             printf("NO
    ");
    80         else
    81             printf("%d
    ", ans);
    82     }
    83     return 0;
    84 }
    View Code


    2.3(二维判重,推荐使用):

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <vector>
     7 #include <queue>
     8 #include <stack>
     9 #include <map>
    10 #include <string>
    11 #include <set>
    12 #define ms(a,b) memset((a),(b),sizeof((a)))
    13 using namespace std;
    14 typedef long long LL;
    15 const int INF = 2e9;
    16 const LL LNF = 9e18;
    17 const int MOD = 1e9+7;
    18 const int MAXN = 100+10;
    19 
    20 struct node
    21 {
    22     int con[3], step;
    23 };
    24 int vol[3], vis[MAXN][MAXN];
    25 
    26 queue<node>que;
    27 int bfs()
    28 {
    29     ms(vis,0);
    30     while(!que.empty()) que.pop();
    31 
    32     node now, tmp;
    33     now.con[0] = vol[0];
    34     now.con[1] = now.con[2] = 0;
    35     now.step = 0;
    36     vis[now.con[0]][now.con[1]] = 1;
    37     que.push(now);
    38 
    39     while(!que.empty())
    40     {
    41         now = que.front();
    42         que.pop();
    43 
    44         if((now.con[0]==vol[0]/2 && now.con[1]==vol[0]/2)
    45            || (now.con[0]==vol[0]/2 && now.con[2]==vol[0]/2)
    46            || (now.con[1]==vol[0]/2 && now.con[2]==vol[0]/2))
    47                 return now.step;
    48 
    49         for(int i = 0; i<3; i++)    //模拟倒水的过程
    50         for(int j = 0; j<3; j++)
    51         {
    52             if(i==j) continue;
    53             tmp = now;
    54             int pour = min(tmp.con[i], vol[j]-tmp.con[j]);
    55             tmp.con[j] += pour;
    56             tmp.con[i] -= pour;
    57             if(!vis[tmp.con[0]][tmp.con[1]])
    58             {
    59                 vis[tmp.con[0]][tmp.con[1]] = 1;
    60                 tmp.step++;
    61                 que.push(tmp);
    62             }
    63         }
    64     }
    65     return -1;
    66 }
    67 
    68 int main()
    69 {
    70     while(scanf("%d%d%d",&vol[0], &vol[1], &vol[2]) && (vol[0]||vol[1]||vol[2]))
    71     {
    72         if(vol[0]%2)
    73         {
    74             printf("NO
    ");
    75             continue;
    76         }
    77         int ans = bfs();
    78         if(ans==-1)
    79             printf("NO
    ");
    80         else
    81             printf("%d
    ", ans);
    82     }
    83     return 0;
    84 }
    View Code
  • 相关阅读:
    我们的CPU遭到攻击[LOJ558]
    历史[ZJOI2018]
    字符串[LOJ6517]
    奥运公交[LOJ3255]
    BLO-Blockade[POI2008]
    压力[BJOI2013]
    Earthquake[USACO01OPEN]
    暴力写挂[CTSC2018]
    极简教程:数据结构与算法(二)
    DllRegisterServer的调用失败的问题解决方法
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7538593.html
Copyright © 2011-2022 走看看