POJ 3414 Pots

来源:互联网 发布:linux shell cut 编辑:程序博客网 时间:2024/06/15 08:52
Pots
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 15123 Accepted: 6359 Special Judge

Description

You are given two pots, having the volume of A and B liters respectively. The following operations can be performed:

  1. FILL(i)        fill the pot i (1 ≤ ≤ 2) from the tap;
  2. DROP(i)      empty the pot i to the drain;
  3. POUR(i,j)    pour from pot i to pot j; after this operation either the pot j is full (and there may be some water left in the pot i), or the pot i is empty (and all its contents have been moved to the pot j).

Write a program to find the shortest possible sequence of these operations that will yield exactly C liters of water in one of the pots.

Input

On the first and only line are the numbers AB, and C. These are all integers in the range from 1 to 100 and C≤max(A,B).

Output

The first line of the output must contain the length of the sequence of operations K. The following K lines must each describe one operation. If there are several sequences of minimal length, output any one of them. If the desired result can’t be achieved, the first and only line of the file must contain the word ‘impossible’.

Sample Input

3 5 4

Sample Output

6FILL(2)POUR(2,1)DROP(1)POUR(2,1)FILL(2)POUR(2,1)

Source

Northeastern Europe 2002, Western Subregion

special judge 我的理解是,有多个答案吧,你只需要出来一个正确的答案就算正确,

题意大致就是给你两个杯子和一个你需要达到的水的升数,不妨,我就假设为三杯水,前两个为容器,第三个已经给你了,让你用前两个相互倒水,达到第三个杯子的水量(不知道这么说是复杂了还是简单了)

一看这个题,觉得是暴力搜索,然而剪枝不怎么会,去网上扒拉了一下他们的代码,发现有个很简单的方法我在这里说说大体意思:如果两个杯子互为倍数关系,而且打三个杯子和前两个不是倍数关系,那么就一定达不到。对于一般的情况,无外乎从第一个杯子倒入第二个杯子,如果第二个杯子满了,那么就清空第二个杯子,如果第一个杯子空了,就倒满第一个杯子,那么最后一定会出来结果;或者是从第二个杯子倒入第一个杯子,如果第一个杯子满了,就清空第一个杯子,如果第二个杯子空了,就加满他,一直循环下去。这两个方式中一定有一个是最好的,里面会用到sscanf()函数,不懂得可以去看看这个博客http://blog.csdn.NET/i1020/article/details/53557116, 我们在这里用的也是很简单的,不看也差不多。

这里附上ac代码

#include <stdio.h>char str1[5000][20],str2[5000][20];int main(){int a,b,c,cnt1,cnt2,i,j;while(~scanf("%d%d%d",&a,&b,&c)){int t1 = a > b ? a : b;int t2 = a + b - t1;cnt1 = 0;if(t1 % t2 == 0 && c % t2 !=0)//判断是否能够产生c升 printf("impossible\n");else{i=0;j=0;//i代表第二个杯子,j代表第一个杯子while(i!=c&&j!=c){if(!i){//如果第二个杯子是空的,就给他倒水 i=b;sscanf("FILL(2)\n","%s",str1[cnt1++]);}else if(j == a) {//如果第一个杯子满了,就倒掉 j=0;sscanf("DROP(1)\n","%s",str1[cnt1++]);}else{//所有情况上面都判断过了,然后开始倒水 int tmp=i;//备份一下现在的水量i=i-(a-j);//i编程倒完后的剩余量sscanf("POUR(2,1)\n","%s",str1[cnt1++]);if(i<0)//这时候是第一个杯子太大,i = 0;j=j + tmp;//倒进来if(j > a)//第一个杯子放不下了 j=a; }//这只是走了一步,每一步都回到while循环,每一步都判断是否达到额定的水量 }//现在开始第二种走法i=0;j=0;cnt2=0;while(i!=c&&j!=c){if(!j){//如果第一个杯子是空的,就给他倒水 j=a;sscanf("FILL(1)\n","%s",str2[cnt2++]);}else if(i == b) {//如果第二个杯子满了,就倒掉 i=0;sscanf("DROP(2)\n","%s",str2[cnt2++]);}else{//所有情况上面都判断过了,然后开始倒水 int tmp=j;//备份一下现在的水量j=j-(b-i);//i编程倒完后的剩余量sscanf("POUR(1,2)\n","%s",str2[cnt2++]);if(j<0)//这时候是第二个杯子太大,j = 0;i=i + tmp;//倒进来if(i > b)//第二个杯子放不下这么多水 i=b; }//这只是走了一步,每一步都回到while循环,每一步都判断是否达到额定的水量 }printf("%d\n",cnt1 < cnt2 ? cnt1 : cnt2);//选择最小的输出if(cnt1 > cnt2){              for(i = 0; i < cnt2; i ++)                  printf("%s\n",str2[i]);          }          else{              for(i = 0; i < cnt1; i ++)                  printf("%s\n",str1[i]); } }} return 0;}

第二种方法就是用bfs搜索,因为bfs的特点就是出来最优解

我简单说一下模型,总共6种转移:清空1,清空2,满1,满2,1到2,2到1。bfs遍历一遍就行,

注意到 A 和 B 的范围是 1 到 100 的整数,
那么我们可以用vis[i][j]来记录每一种状态 0 <= i, j <= 100 ;
 i 表示目前 A 容器中的水, j 表示目前 B 容器中的水

这6种操作在我的程序中分别用一个整数进行记录;

1z0: 清空z瓶子

2z0: 装满z瓶子

3xy: 从x瓶倒向y瓶

(x,y,z∈{1,2})

这样在输出操作时就能根据数字的特点 进行选择性输出 了

输出用的递归输出

ac代码:

#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#define INF 110using namespace std;int a,b,c;//容器大小和要达到的容量值 int vis[INF][INF];//标记数组,记录一个个状态是否发生过 struct node{int k1,k2;//当前水的状态 int dd;//当前进行的操作 int pre;//记录他的父节点 int step;//记录步数 }nn[12105];//其实INF*INF就可 int dir[6]={110,120,210,220,312,321};//分别代表六种状态 void output(node t){if(t.pre!=-1){output(nn[t.pre]);if(t.dd==110){printf("FILL(1)\n");}else if(t.dd==120){printf("FILL(2)\n");}else if(t.dd==210){printf("DROP(1)\n");}else if(t.dd==220){printf("DROP(2)\n");}else if(t.dd==312){printf("POUR(1,2)\n");}else if(t.dd==321){printf("POUR(2,1)\n");}}elsereturn ;}int bfs(){int i,j,falg=0,front,rear;nn[0].k1=0;nn[0].k2=0;nn[0].dd=0;nn[0].step=0;nn[0].pre=-1;//代表无前驱 front=0;rear=1;memset(vis,0,sizeof(vis));vis[0][0]=1;//初始状态已经发生过 while( front < rear )//没走一遍 {if(nn[front].k1==c || nn[front].k2==c){//应该不会出现这种情况,既c=0; printf("0\n");return 1;}for(i=0;i<6;i++){//六种状态全部进行一遍 node tmp;if(dir[i]==110){tmp.k1=a;tmp.k2=nn[front].k2;}else if(dir[i]==120){tmp.k2=b;tmp.k1=nn[front].k1;}else if(dir[i]==210){tmp.k1=0;tmp.k2=nn[front].k2;}else if(dir[i]==220){tmp.k2=0;tmp.k1=nn[front].k1;}else if(dir[i]==312){if(nn[front].k1+nn[front].k2 < b){tmp.k2=nn[front].k1+nn[front].k2;tmp.k1=0;}else{tmp.k2=b;tmp.k1=nn[front].k1+nn[front].k2-b;}}else if(dir[i]==321){if(nn[front].k1+nn[front].k2 < a){tmp.k1=nn[front].k1+nn[front].k2;tmp.k2=0;}else{tmp.k1=a;tmp.k2=nn[front].k1+nn[front].k2-a;}}tmp.dd=dir[i];tmp.pre=front;tmp.step=nn[front].step+1;if(!vis[tmp.k1][tmp.k2])//当前状态未经历过{vis[tmp.k1][tmp.k2]=1;nn[rear]=tmp;rear++;if(tmp.k1==c||tmp.k2==c){printf("%d\n",tmp.step);output(nn[rear-1]);return 1;}} }front++;}return 0;}int main(){int flag;while(~scanf("%d%d%d",&a,&b,&c)){flag=0;flag=bfs();if(!flag){printf("impossible\n");}}return 0;}


1 0
原创粉丝点击