POJ 3414 --Pots (BFS+路径输出)

题意: 你有两个罐子,容量分别为a,b;开始时都没水,要通过给定的三种操作,使得其中一个罐子的水量恰好为c,若存在操作使之成立,输出最少操作数及对应的每步操作;否则输出impossible。

思路: 由于a,b,c的范围很小为1到100且要求最小操作数,故考虑采用bfs,即搜索可能的情况若有到达其中一个罐子里的水为c的情况则搜索结束并输出路径,否则直到队列为空后输出impossible。
对于路径的输出,用于a,b的范围都在100之内,故开一个100*100的数组pre即可存储所有可能的搜索情况,pre数组的作用是记录bfs中当前状态的前一个转移过来的状态,输出时用栈将数据倒过来即可。
(第一次写时采用在结构体中新开一个node * pre来记录前驱,但是指针涉及到了动态开空间会超时…)

AC代码(pre数组记录前驱):

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#include<string>
#include<stack>
using namespace std;
#define maxn 105

bool vis[maxn][maxn];//标记已经搜过的状态,避免重复搜索; 
string op[]={"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};

struct node{
	int x,y;
	int step;
	int id;
};
struct pre{
	int id;
	int operation;
}pre[maxn*maxn];//存前驱节点; 
int a,b,c;

void get_ans(node now)
{
	printf("%d\n",now.step);
	
	stack<int>st;
	while(!st.empty()) st.pop();
	
	int pos=now.id;
	while(pre[pos].id!=-1)
	{
		st.push(pre[pos].operation);
		pos=pre[pos].id;
	}
	
	while(!st.empty())
	{
		int t=st.top();
		st.pop();
		cout<<op[t]<<endl;
	}
}

void bfs()
{
	queue<node>q;
	int pos=0;//记录是第几个状态,便于找路径; 
	while(!q.empty()) q.pop();
	memset(vis,false,sizeof(vis));
	node s;
	s.x=0;
	s.y=0;
	s.step=0;
	s.id=0;
	pre[0].id=-1;
	pre[0].operation=-1;
	vis[0][0]=true;
	q.push(s);
	
	while(!q.empty())
	{
		node now=q.front();
		q.pop();
		if(now.x==c||now.y==c)
		{
			get_ans(now);
			return ;
		}
		
		node in;
		in.step=now.step+1;
		
		//1.a装满;
		if(now.x>=0 && now.x<a && (!vis[a][now.y]))
		{
			in.x=a;
			in.y=now.y;
			in.id=(++pos);
			pre[in.id].operation=0;
			pre[in.id].id=now.id;
			q.push(in);
			vis[in.x][in.y]=true;
		} 
		
		//2.b装满;
		if(now.y>=0 && now.y<b && (!vis[now.x][b]))
		{
			in.x=now.x;
			in.y=b;
			in.id=(++pos);
			pre[in.id].operation=1;
			pre[in.id].id=now.id;
			q.push(in);
			vis[in.x][in.y]=true;
		}
		
		//3.a倒空;
		if(now.x>0 && (!vis[0][now.y]))
		{
			in.x=0;
			in.y=now.y;
			in.id=(++pos);
			pre[in.id].operation=2;
			pre[in.id].id=now.id;
			q.push(in);
			vis[in.x][in.y]=true;
		}
		
		//4.b倒空;
		if(now.y>0 && (!vis[now.x][0]))
		{
			in.x=now.x;
			in.y=0;
			in.id=(++pos);
			pre[in.id].operation=3;
			pre[in.id].id=now.id;
			q.push(in);
			vis[in.x][in.y]=true;
		} 
		
		//5.a能够全部倒入b中;
		if(now.x>0 && now.x+now.y<=b && (!vis[0][now.x+now.y]))
		{
			in.x=0;
			in.y=now.x+now.y;
			in.id=(++pos);
			pre[in.id].operation=4;
			pre[in.id].id=now.id;
			q.push(in);
			vis[in.x][in.y]=true;
		} 
		
		//6.b能够全部倒入a中;
		if(now.y>0 && now.x+now.y<=a && (!vis[now.x+now.y][0]))
		{
			in.x=now.x+now.y;
			in.y=0;
			in.id=(++pos);
			pre[in.id].operation=5;
			pre[in.id].id=now.id;
			q.push(in);
			vis[in.x][in.y]=true;
		}
		
		//7.a只有部分能倒入b中;
		if(now.x>0 && now.x+now.y>b && (!vis[now.x-(b-now.y)][b]))
		{
			in.x=now.x-(b-now.y);
			in.y=b;
			in.id=(++pos);
			pre[in.id].operation=4;
			pre[in.id].id=now.id;
			q.push(in);
			vis[in.x][in.y]=true;
		 } 
		 
		//8.b只有部分能倒入a中;
		if(now.y>0 && now.x+now.y>a && (!vis[a][now.y-(a-now.x)]))
		{
			in.x=a;
			in.y=now.y-(a-now.x);
			in.id=(++pos);
			pre[in.id].operation=5;
			pre[in.id].id=now.id;
			q.push(in);
			vis[in.x][in.y]=true;
		} 
	}
	printf("impossible\n");
}

int main()
{
	scanf("%d%d%d",&a,&b,&c);
	bfs();
	
	return 0;
}

超时代码(node* pre结构体指针记录前驱):

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<iostream>
#include<string>
#include<stack>
using namespace std;

bool vis[105][105];//标记已经搜过的状态,避免重复搜索; 
string op[]={"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};
struct node{
	int x,y;
	int step;
	int operation;
	node* pre;
};
int a,b,c;

void bfs()
{
	queue<node>q;
	while(!q.empty()) q.pop();
	memset(vis,false,sizeof(vis));
	
	node* s=(node*)malloc(sizeof(node));
	s->x=0;
	s->y=0;
	s->step=0;
	q.push(*s);
	s->pre=NULL;
	vis[0][0]=true;
	
	while(!q.empty())
	{
		node* now=(node*)malloc(sizeof(node));
		now=&q.front();
		q.pop();
		
		if(now->x==c||now->y==c)//有一个罐子满足终止条件
		{
			printf("%d\n",now->step);
			stack<int>st;
			while(!st.empty()) st.pop();
			
			while(now->pre!=NULL)
			{
				st.push(now->operation);
				now=now->pre;
			}
			
			while(!st.empty())
			{
				int t=st.top();
				st.pop();
				cout<<op[t]<<endl;
			}
			
			return ;
		 } 
		
		node* in=(node*)malloc(sizeof(node));
		in->step=now->step +1;
		in->pre=now;
		
		//1.a装满; 
		if(now->x>=0 && now->x<a && (!vis[a][now->y]))
		{
			in->x=a;
			in->y=now->y;
			now->operation=0;
			q.push(*in);
			vis[in->x][in->y]=true;
		}
		
		//2.b装满; 
		if(now->y >=0 && now->y<b &&(!vis[now->x][b]))
		{
			in->x=now->x;
			in->y=b;
			now->operation=1;
			q.push(*in);
			vis[in->x][in->y]=true;
		}
		
		//3.a倒空;
		if(now->x>0 && (!vis[0][now->y]))
		{
			in->x=0;
			in->y=now->y;
			now->operation=2;
			q.push(*in);
			vis[in->x][in->y]=true;
		}
		
		//4.b倒空;
		if(now->y>0 && (!vis[now->x][0]))
		{
			in->x=now->x;
			in->y=0;
			now->operation=3;
			q.push(*in);
			vis[in->x][in->y]=true;
		}
		
		//5.能把a全部倒入b;
		if(now->x>0 && now->y+now->x <=b && (!vis[0][now->x+now->y]))
		{
			in->x=0;
			in->y=now->x+now->y;
			now->operation=4;
			q.push(*in); 
			vis[in->x][in->y]=true;
		 } 
		 
		//6.能把b全部倒入a;
		if(now->y>0 && now->x+now->y <=a && (!vis[now->x+now->y][0]))
		{
			in->x=now->x+now->y;
			in->y=0;
			now->operation=5;
			q.push(*in);
			vis[in->x][in->y]=true;
		}
		
		//7.只能倒一部分a到b中;
		if(now->x>0 && now->x+now->y >b && (!vis[now->x-(b-now->y)][b]))
		{
			in->x=now->x-(b-now->y);
			in->y=b;
			now->operation=4;
			q.push(*in);
			vis[in->x][in->y]=true;
		} 
		
		//8.只能倒一部分b到a中;
		if(now->y>0 && now->x+now->y >a && (!vis[a][now->y-(a-now->x)]))
		{
			in->x=a;
			in->y=now->y-(a- now->x);
			now->operation=5;
			q.push(*in);
			vis[in->x][in->y]=true;
		 } 
	}
	printf("impossible\n");
}

int main()
{
	int i,j;
	scanf("%d%d%d",&a,&b,&c);
	bfs();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值