zoukankan      html  css  js  c++  java
  • uva10603 解题报告

    uva10603 Fill 倒水问题 解题报告:

    题目链接:https://uva.onlinejudge.org/external/106/10603.pdf

    题目大意:

    设3个杯子的容量为abc,起初只有第三个杯子装满了c升水。其它两个杯子均为空。最少要倒多少升水可以让某一个杯子里有d升水。如果无法做到d升水。就让某个杯子里有d‘升水,其中d’<d而且尽量接近d(1<=a,b,c,d<=200)要求输出最小的倒水量和目标水量(d或者是d‘)

    分析:

    这个样子其实有一点点动态规划的味道,其实不是。一看到这种求最小的倒水量。第一眼就应该想到用BFS。广搜,可以完美的设计到这种状态或者是抉择问题。而这道题。3个杯子,假设在某一时刻第一个杯子里有v1升水。第二个杯子有v2升水,第三个杯子有v3升水。而这个时候可以说是在某一时刻的状态。“状态”这个名词很玄学,往往有很多的算法和思想都会运用到状态这个概念。而每个状态之间都可以通过某种方式进行转换,这道题就是通过倒水。

    循环来两,两倒水,倒出后的结果放到一个新的状态,新的状态进队。(进队之前要判重。)理论上就有 (a+1)(b+1)(c+1)=8120601种状态,这个状态有点多。内存有点多。但是呢,这种判断是不精确的。因为,水就那么多。当a,b的量确定之后,c的量就确定了,所以这么大的状态就一下缩小到201^2=40401;这就小多了。

    而在一般的BFS中目标状态最先搜索到的一定是步骤最小的一个目标状态,而这道题求的不是最小步骤的目标状态而是倒水量最小的目标状态,所以,这里的队列应该用到优先队列,优先队列里的判断条件就是根据每种状态的倒水量的大小,来判断。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<string.h>
     4 #include<queue>
     5 using namespace std;
     6 struct node{  //每种状态
     7     int v[4];
     8     int num;
     9 }start;
    10 bool operator < (const node &a,const node &b) //这个东西是用来给优先队列判断优先级用的。很迷,不是很懂。
    11 {
    12     return a.num>b.num;
    13 }
    14 int judge[4],d,ans[205];
    15 int visit[201][201],mark[201][201]; 
    16 int until_ans(node n)//当一种状态出现的时候,要对里面的每一杯水之后的倒水量进行一个存储,ans[i]代表当杯子里出现i升水时,最小的倒水量。
    17 {
    18     for(int i=1;i<=3;i++)
    19     {
    20         int b;
    21         b=n.v[i];
    22         if(ans[b]<0||n.num<ans[b])ans[b]=n.num;
    23     }
    24     return 0;
    25 }
    26 void bfs()
    27 {
    28     priority_queue<node> q;
    29     memset(visit,0,sizeof(visit));
    30     memset(mark,0,sizeof(mark));
    31     start.v[1]=0;start.v[2]=0;start.v[3]=judge[3];start.num=0;
    32     q.push(start); //初始状态
    33     visit[0][0]=1;
    34     while(!q.empty())
    35     {
    36         node now=q.top();
    37         q.pop();
    38         if(mark[now.v[1]][now.v[2]])continue;
    39         mark[now.v[1]][now.v[2]]=1;
    40         until_ans(now);//记录出现杯子里的水的时候,总倒水量。
    41         if(ans[d]>0)break;//找到目标状态。
    42         for(int i=1;i<=3;i++)//枚举杯子
    43             for(int j=1;j<=3;j++)
    44             if(i!=j)//自己不能给自己倒
    45             {
    46                 node now_1;
    47                 memcpy(&now_1,&now,sizeof(now));
    48                 if(now_1.v[i]==0||now_1.v[j]==judge[j])continue;//当当前状态要倒出的杯子没水或者被倒水的杯子满的就不能倒。
    49                 int water=min(judge[j],now_1.v[i]+now_1.v[j])-now_1.v[j];//判断到底倒多少水。这个得自己理解。
    50                 now_1.num+=water;
    51                 now_1.v[i]-=water;
    52                 now_1.v[j]+=water;
    53                 if(!visit[now_1.v[1]][now_1.v[2]])//如果当前状态没出现,就入队。
    54                 {
    55                     q.push(now_1);
    56                     visit[now_1.v[1]][now_1.v[2]]=1;
    57                 }
    58             }
    59     }
    60     while(d>=0)//枚举答案。
    61     {
    62         if(ans[d]>=0){
    63             printf("%d %d
    ",ans[d],d);
    64             return ;
    65         }
    66         d--;//当目标答案没有的时候,就往前找。(依照题目要求)
    67     }
    68 }
    69 int main()
    70 {
    71     int n;
    72     scanf("%d",&n);
    73     while(n--)
    74     {
    75         scanf("%d%d%d%d",&judge[1],&judge[2],&judge[3],&d);
    76         memset(ans,-1,sizeof(ans));
    77         bfs();
    78     }
    79     return 0;
    80 }

     

  • 相关阅读:
    转自苦大师:移动测试Appium之API手册
    怨念与发飙
    Asp.Net 2.0新特性
    汉字是最优美的文字
    加入cnblog留念
    Thrift之TProtocol类体系原理及源码详细解析之其他协议类和总结
    Thrift之TProtocol类体系原理及源码详细解析之二进制协议类TBinaryProtocolT(TBinaryProtocol)
    linux内核bug问题排查过程详细报告
    Thrift之TProtocol类体系原理及源码详细解析之紧凑协议类TCompactProtocolT(TCompactProtocol)
    Thrift之TProcess类体系原理及源码详细解析
  • 原文地址:https://www.cnblogs.com/uncle-lu/p/5884766.html
Copyright © 2011-2022 走看看