您的位置:首页 > 其它

POJ3414Pots(AC)

2015-11-18 10:11 363 查看
Pots

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 12571 Accepted: 5300 Special Judge
Description

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

FILL(i)        fill the pot i (1 ≤ i ≤ 2) from the tap;
DROP(i)      empty the pot i to the drain;
POUR(i,j)    pour from pot i to pot j; after this operation either the potj is full (and there may be some water left in the poti), or the poti is empty (and all its contents
have been moved to the potj).
Write a program to find the shortest possible sequence of these operations that will yield exactlyC liters of water in one of the pots.

Input

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

Output

The first line of the output must contain the length of the sequence of operationsK. The followingK 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
6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)

 
<pre class="cpp" name="code">#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

/*对于这道题有个疑问是FILL(i)这个第i个盆弄满,那到底多少毫升算是弄满,是不是这样的3 5 4中的3 5 分别表示第一个的体积是3,第2个的体积是5,应该是这样的,要不然没别的解释*/
/*上面的理解是对的,而且这道题还要输出路径的,这个也要注意的,不光光是输出最小步数的*/

//这个还要输出路径的,要注意,输出路径也是有难度的

//这个是只要任意一个得到残余水量就行,自己开始理解的不对,以为2个都要达到----这个是看了提示题目之前就看的,所以一直记的是2个都达到要求的水量,是不对的

//同时还有一个要输出impossible的情况

/*第一次提交Runtime Error运行时出错了,自己没有做visit的操作,这个是看了说明之后才知道要设visit的,因为自己认为相同的操作是可以的,大错误,直接导致都溢出了
但是直接用visit数组又不对,这样最大就6个操作肯定不对*/
/*怎么进行控制呢。。。本题关键就是这个visit到底是设的什么?ttp://blog.csdn.net/lyy289065406/article/details/6647930 这里讲了这题的2个难点,其中第2个就是状态
记录,自己一直没弄好的这个后来还是看了很多参考之后,然后得出的状态是如果pot1和pot2残留的水量曾经有过,就不要操作了,否则就是多余操作的,,然后就AC了*/

/*测试数据
1 5 2
3 5 4*/

/*POJ AC*/

#define MAXINT 1000

#define MAX(a,b)  ((a)<(b)?(b):(a))

int pot1 = 0; //pot1最多可以放的液体数
int pot2 = 0;
int aim = 0;
int back = 0;//采用只有back不用front的方法,BFS要慢慢用这种方法,这样可以有效的减少que的空间大小,这题不适合用覆盖的方法,因为要求路径啊
int front= 0;

#define FILL (1)
#define POUR (2)
#define DROP (3)

typedef struct nodes
{
char operation[20]; //存放动作
int src;   //源
int des;  //目的 比如POUR(2,1),2-src,1-des
int step;
int pot1;
int pot2;  //存放当前各pot中的液体数,也就是做了本次操作后各pot的液体数
int fatherindex;
}node;

node que[MAXINT];
int  visit[MAXINT][MAXINT];
int ans = 0;

void insert(int type, int p1, int p2, int src, int des, int step,int fatherIndex)
{
if (FILL == type)
{
que[back].operation[0] = 'F';
que[back].operation[1] = 'I';
que[back].operation[2] = 'L';
que[back].operation[3] = 'L';
}
else if (DROP == type)
{
que[back].operation[0] = 'D';
que[back].operation[1] = 'R';
que[back].operation[2] = 'O';
que[back].operation[3] = 'P';
}
else
{
que[back].operation[0] = 'P';
que[back].operation[1] = 'O';
que[back].operation[2] = 'U';
que[back].operation[3] = 'R';
}
que[back].src         = src;
que[back].des         = des;
que[back].fatherindex = fatherIndex;
que[back].pot1        = p1;
que[back].pot2        = p2;
que[back++].step      = step;
return;
}

void GetPath(int index,int father)
{
int i = 0;
int num = 0;
int path[10000]; //记录Index
path[num++] = index;
while (-1 != father)
{
index = father;
path[num++] = index;
father = que[father].fatherindex;
}
for (i = (num-1); i > 0;i--)
{
if (('D' == que[path[i]].operation[0]) || ('F' == que[path[i]].operation[0]))
{
printf("%c%c%c%c(%d)\n", que[path[i]].operation[0], que[path[i]].operation[1], que[path[i]].operation[2], que[path[i]].operation[3], que[path[i]].src);
}
else
{
printf("%c%c%c%c(%d,%d)\n", que[path[i]].operation[0], que[path[i]].operation[1], que[path[i]].operation[2], que[path[i]].operation[3], que[path[i]].src, que[path[i]].des);
}
}
}

void bfs()
{
int fix1 = 0;
int fix2 = 0;//存放的pot中液体数
int p1 = 0;
int p2 = 0;
int sp   = 0;
int i = 0;
int father = -1;
int mark = 0;
//每个操作可以有FILL(1),FILL(2),POUR(2,1),POUR(1,2),DROP(1),DROP(2) 应该是有这么多操作的可能性
//开始的时候只可能由FILL的操作,不可能有POUR和DROP,因为刚开始的时候都是空的
for (i = 1; i<=2; i++)
{
que[back].operation[0] = 'F';
que[back].operation[1] = 'I';
que[back].operation[2] = 'L';
que[back].operation[3] = 'L';
que[back].src          = i;
que[back].fatherindex  = -1;
if (1 == i)
{
que[back].pot1 = pot1;
que[back].pot2 = 0;
visit[pot1][0] = 1;
}
else
{
que[back].pot1 = 0;
que[back].pot2 = pot2;
visit[0][pot2] = 1;
}
que[back++].step = 1;
}

while (front < back)
{
fix1 = que[front].pot1;
fix2 = que[front].pot2;
sp    = que[front].step;
father = front;

if ((aim == fix1) || (aim == fix2))
{
ans = que[front].step;
printf("%d\n", ans);
GetPath(front ,father);
return;
}

//原来以为之前是什么操作,后面可能就不会有相同的操作,其实这是不对的,fill操作也可以紧跟fill操作
//因为fill(1)后面可以是fill(2),而且不区分代码也会简洁一点,否则会有很多重复代码
//drop操作
for (i = 1; i <= 2; i++)
{
if ((1 == i) && (fix1 >0))//drop(1)
{
p1 = 0;
p2 = fix2;
if (0 == visit[p1][p2])
{
insert(DROP, p1, p2, i, 0, sp + 1, father);
//SetVisit(DROP, i, 0);
visit[p1][p2] = 1;
}

}
else if ((2 == i) && (fix2 >0))//drop(2)
{
p1 = fix1;
p2 = 0;

if (0 == visit[p1][p2])
{
insert(DROP, p1, p2, i, 0, sp + 1, father);
visit[p1][p2] = 1;
}
}
}

//pour操作
for (i = 1; i <= 2; i++)
{
if (1 == i) //pour(1,2)
{
if (fix1 > 0)
{
//1往2里面倒
if ((pot2 - fix2) >= fix1) //p1都倒完了
{
p2 = fix2 + fix1;
p1 = 0;
}
else
{
p2 = pot2;
p1 = fix1 + fix2 - pot2;
}

if (0 == visit[p1][p2])
{
insert(POUR, p1, p2, 1, 2, sp + 1, father);
//SetVisit(POUR, 1, 2);
visit[p1][p2] = 1;
}
}
}
else
{//pour(2,1)

/*2往1里面倒*/
if (fix2 > 0)
{
if ((pot1 - fix1) >= fix2)
{
p1 = fix1 + fix2;
p2 = 0;
}
else
{
p1 = pot1;
p2 = fix2 + fix1 - pot1;
}

if (0 == visit[p1][p2])
{
insert(POUR, p1, p2, 2, 1, sp + 1, father);
//SetVisit(POUR, 2, 1);
visit[p1][p2] = 1;
}
}
}

}

//FILL操作
for (i = 1; i <= 2; i++)
{
if ((1 == i) && (fix1 <pot1))//fill(1)
{
p1 = pot1;
p2 = fix2;
if (0 == visit[p1][p2])
{
insert(FILL, p1, p2, i, 0, sp + 1, father);
//SetVisit(FILL, i, 0);
visit[p1][p2] = 1;
}

}
else if ((2 == i) && (fix2 <pot2))//fill(2)
{
p1 = fix1;
p2 = pot2;
if (0 == visit[p1][p2])
{
insert(FILL, p1, p2, i, 0, sp + 1, father);
//SetVisit(FILL, i, 0);
visit[p1][p2] = 1;
}
}
}

front++;
}

printf("impossible\n");
return;
}

void init()
{
int i = 0;
int j = 0;
for (i = 0; i < MAXINT;i++)
{
for (j = 0; j < MAXINT; j++)
{
visit[i][j] = 0;
}
}
ans = 0;
return;
}

int main()
{
int maxint = 0;
freopen("input.txt","r",stdin);
scanf("%d %d %d", &pot1, &pot2,&aim);
init();
maxint = MAX(pot1, pot2); //这个是看了discuss后加的,最开始觉得不需要加这个判断,输入会控制的,还是要加下,否则用3 4 5 我的堆栈直接爆了
if (aim <= maxint)
{
bfs();
}
else
{
printf("impossible\n");
}

return 0;
}


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: