H - Pots

给你两个容器,分别能装下A升水和B升水,并且可以进行以下操作
FILL(i) 将第i个容器从水龙头里装满(1 ≤ i ≤ 2);
DROP(i) 将第i个容器抽干
POUR(i,j) 将第i个容器里的水倒入第j个容器(这次操作结束后产生两种结果,一是第j个容器倒满并且第i个容器依旧有剩余,二是第i个容器里的水全部倒入j中,第i个容器为空)
现在要求你写一个程序,来找出能使其中任何一个容器里的水恰好有C升,找出最少操作数并给出操作过程

Input
有且只有一行,包含3个数A,B,C(1<=A,B<=100,C<=max(A,B))

Output
第一行包含一个数表示最小操作数K
随后K行每行给出一次具体操作,如果有多种答案符合最小操作数,输出他们中的任意一种操作过程,如果你不能使两个容器中的任意一个满足恰好C升的话,输出“impossible”

Sample Input
3 5 4
Sample Output
6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)

这是一道非常恶心的BFS的题,不但要找出最短路径(到达c的最短路),还要记录路径过程,这里用的结构的特性定义了数组pre[][],用pre[x][y]中的x,y来表示两个容器分别到达x,y两种状态,用pre[x][y].x和pre[x][y].y和pre[x][y].step来表示下x,y的状态是由pre[x][y].x和pre[x][y].x通过step来到达,通过一个递归函数pr来输出操作路径,这个递归函数先递归到最后一层到x,y都为零,这是结束标志,再从里到外一层一层的输出,最后便是从先到后的操作方法输出,(这是一种用递归函数从外递到内,内也就是最先的操作方法,再从外到内一层一层的输出),对还有,再进行bfs时利用vis[][]剪枝,到一种状态时,判断是不是第一次到达,如果是就利用vis[][]标记一下这个状态到达过,因为在bfs里第一次到达这个状态也是最快到达这个状态,也就是通过最少的操作数到达的路径,其后面到达这个1状态的就可以舍去了,因为肯定后面到达此状态的操作数比第一个到达的多,所以舍去,如果是并列到达一种状态,随意取一个即可,都是通过同样的操作数到达,而且题目只要求随意一写出一个即可,通过剪枝才不会时间超限;

通过这几天对搜索的学习,总结一下:对于dfs,主要是对于一个点直接递归到最低,如果不行,再对另一个方向递归到低;而对于bfs,是对一个点可以到达的所有的状态,进行列举,把状态列出来放入队列中,每去一个点都要都周围中的所有状态进行列举放入队列,最后指导搜到结果,bfs一般用来搜索最短路径,如此题,bfs通常使用到队列,而且队列里都是pair或者自己的写的结构;对于搜索较为难一些的是需要剪枝的;
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<iostream>
using namespace std;
const int INF = 0x3f3f3f3f;
struct node 
{
	int x,y;
	int step;
}pre[10001][10001];
int vis[102][102],a,b,c,now[3],limt[3],tt[3],ans1,ans2;
node t,d;
int bfs()
{
	t.x=now[0];
	t.y=now[1];
	t.step=0;
	vis[t.x][t.y]=1;
	queue<node>q;
	q.push(t);
	while(!q.empty())
	{
		t=q.front();
		q.pop();
		now[0]=t.x;
		now[1]=t.y;
		if(t.x==c||t.y==c)
		{
			ans1=t.x;
			ans2=t.y;
			return t.step;
		}
		/*将第一个倒满;*/ 
		tt[0]=now[0];
		tt[1]=now[1];
		d.x=limt[0];
		d.y=now[1];
		d.step=t.step+1;
		if(vis[d.x][d.y]==0)
		{
			vis[d.x][d.y]=1;
		q.push(d);
		pre[d.x][d.y].x=t.x;
		pre[d.x][d.y].y=t.y;
		pre[d.x][d.y].step=1;	
		}
		now[0]=tt[0];
		now[1]=tt[1];
		/*将第二个倒满*/ 
		tt[0]=now[0];
		tt[1]=now[1];
		d.x=now[0];
		d.y=limt[1];
		d.step=t.step+1;
		if(vis[d.x][d.y]==0)
		{
			vis[d.x][d.y]=1;
			q.push(d);
			pre[d.x][d.y].x=t.x;
			pre[d.x][d.y].y=t.y;
			pre[d.x][d.y].step=2;
		}
		now[0]=tt[0];
		now[1]=tt[1];
		/*将第一个抽干*/ 
		tt[0]=now[0];
		tt[1]=now[1];
		d.x=0;
		d.y=now[1];
		d.step=t.step+1;
		if(vis[d.x][d.y]==0)
		{
			vis[d.x][d.y]=1;
			q.push(d);
			pre[d.x][d.y].x=t.x;
			pre[d.x][d.y].y=t.y;
			pre[d.x][d.y].step=3;
		}
		now[0]=tt[0];
		now[1]=tt[1];
		/*将第二个抽干*/ 
		tt[0]=now[0];
		tt[1]=now[1];
		d.x=now[0];
		d.y=0;
		d.step=t.step+1;
        if(vis[d.x][d.y]==0)
		{
			vis[d.x][d.y]=1;
			q.push(d);
			pre[d.x][d.y].x=t.x;
			pre[d.x][d.y].y=t.y;
			pre[d.x][d.y].step=4;
				}
				now[0]=tt[0];
				now[1]=tt[1];
				/*将第一个导入第二个*/ 
		
		if(now[0]>0)
		{
					tt[0]=now[0];
		tt[1]=now[1];
			if(now[0]>=(limt[1]-now[1]))
			{
				now[0]=now[0]+now[1]-limt[1];
				now[1]=limt[1];
			
			}
			else
			{
			
				now[1]+=now[0];
				now[0]=0;
			}
			d.x=now[0];
			d.y=now[1];
			d.step=t.step+1;
			if(vis[d.x][d.y]==0)
			{
				vis[d.x][d.y]=1;
				q.push(d);
				pre[d.x][d.y].x=t.x;
				pre[d.x][d.y].y=t.y;
				pre[d.x][d.y].step=5;
			}
			now[0]=tt[0];
				now[1]=tt[1];
				}	
				
			/*将第二个导入第一个*/	
			
		if(now[1]>0)
		{
				tt[0]=now[0];
		tt[1]=now[1];
			if(now[1]>=(limt[0]-now[0]))
			{
				 now[1] -= limt[0]-now[0];
                now[0] = limt[0];
			}
			else
			{
				
				now[0]+=now[1];
				now[1]=0;
			}
			   d.x = now[0];
            d.y = now[1];
            d.step = t.step + 1;
            if ( vis[d.x][d.y]==0 ) {
                vis[d.x][d.y] = 1;
                q.push(d);
                pre[d.x][d.y].x = t.x;
                pre[d.x][d.y].y = t.y;
                pre[d.x][d.y].step = 6;
            }

            now[0] = tt[0];
            now[1] = tt[1];
        }
				
	}
	return -1;
}
void pri( int x, int y )  // 对六种情况的编号
{
    if ( x==0 && y==0 ) {
        return ;
    }
    pri(pre[x][y].x,pre[x][y].y);

    if ( pre[x][y].step==1 ) {
        cout << "FILL(1)" << endl;
    }
    if ( pre[x][y].step==2 ) {
        cout << "FILL(2)" << endl;
    }
    if ( pre[x][y].step==3 ) {
        cout << "DROP(1)" << endl;
    }
    if ( pre[x][y].step==4 ) {
        cout << "DROP(2)" << endl;
    }
    if ( pre[x][y].step==5 ) {
        cout << "POUR(1,2)" << endl;
    }
    if ( pre[x][y].step==6 ) {
        cout << "POUR(2,1)" << endl;
    }

}
int main() 
{
	scanf("%d%d%d", &a,&b,&c);
	limt[0]=a;
	limt[1]=b;
	now[1]=0;
	now[0]=0;
	memset(vis,0,sizeof(vis));
	int k=bfs();
	if(k==-1)
	{
		printf("impossible\n");
	}
	else
	{
		printf("%d\n", k);
		pri(ans1,ans2);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值