• 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 }

     

  • 相关阅读:
    npm安装Vue及配置
    Node.js安装
    代码优化总结
    Java 读取文件指定行数的数据
    Navicat Premium 15 v15.0.17 数据库开发工具 安装激活详解
    发现了一个关于 gin 1.3.0 框架的 bug
    802.1X 账号密码+设备信息双重认证
    Vue项目入门(一)
    WPF登录界面
    使用“user32.dll”控制窗体
  • 原文地址:https://www.cnblogs.com/uncle-lu/p/5884766.html
Copyright © 2020-2023  润新知