【BFS+DFS路径输出】 Poj-3414 Pots

题目链接

题目描述

给定两个空杯子容量分别为A, B。 你有六种操作:
1、Fill(i) 把A或者B倒满
2、DROP(i) 把A或者B倒空
3、POUR(i, j) 把 i 倒到 j 里面,不是 i 杯空了就是 j 杯满了
要求:花最少次数使任意一杯被子里面水的容量到C,输出最少次数并记录路径

样例

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

思路

对于求最少次数比较容易,用一个状态量 f [ i ] [ j ] 来表示A杯内部水的量和B杯内部水的量,bfs就行,记录路径的话需要当前状态上一次杯中的水量以及操作,在最后以dfs的方法把路径输出。
这边用 choice 函数记录6种操作,print_path 函数用来打印dfs路径
代码中会提供注释

代码片
#include<cstdio>
#include<queue>
#include<algorithm>
#include<iostream>
#define ll long long
using namespace std;

const int inf=0x3f3f3f3f;

struct Point{
	int step, lx, ly, op;		//op用来记录操作,lx,ly记录上一次状态容器中水的数量 
}f[110][110];
int a,b,c;
struct Volume{
	int a, b;
};

void choice(int x ) {		//6种操作 
	if ( x==1 ) printf("FILL(1)\n");
	else if ( x==2 ) printf("FILL(2)\n");
	else if ( x==3 ) printf("DROP(1)\n");
	else if ( x==4 ) printf("DROP(2)\n");
	else if ( x==5 ) printf("POUR(1,2)\n");
	else if ( x==6 ) printf("POUR(2,1)\n");
}

void bfs(int x, int y) {
	queue<Volume> q;
	Volume now, next;
	now.a=x, now.b=y;
	q.push(now);
	while(!q.empty()) {
		now=q.front(); q.pop();
		int itm=f[now.a][now.b].step+1;		//当前状态+1,表示操作数 
		if ( f[a][now.b].step==-1 ) {
			f[a][now.b].step=itm;
			f[a][now.b].op=1;		//记录操作 
			f[a][now.b].lx=now.a, f[a][now.b].ly=now.b;		//记录上一状态,为了可以dfs打印路径 
			next.a=a, next.b=now.b;
			q.push(next);
		}
		if ( f[now.a][b].step==-1 ) {
			f[now.a][b].step=itm;
			f[now.a][b].op=2;
			f[now.a][b].lx=now.a, f[now.a][b].ly=now.b;
			next.a=now.a, next.b=b;
			q.push(next);
		}
		if ( f[0][now.b].step==-1 ) {
			f[0][now.b].step=itm;
			f[0][now.b].op=3;
			f[0][now.b].lx=now.a, f[0][now.b].ly=now.b;
			next.a=0, next.b=now.b;
			q.push(next);
		}
		if ( f[now.a][0].step==-1 ) {
			f[now.a][0].step=itm;
			f[now.a][0].op=4;
			f[now.a][0].lx=now.a, f[now.a][0].ly=now.b;
			next.a=now.a, next.b=0;
			q.push(next);
		}
		//第五种操作 分为两种情况:被倒入的容器中的水满了或者未满 
		if ( now.a>b-now.b && f[now.a-(b-now.b)][b].step==-1 ) {
			f[now.a-(b-now.b)][b].step=itm;
			f[now.a-(b-now.b)][b].op=5;
			f[now.a-(b-now.b)][b].lx=now.a, f[now.a-(b-now.b)][b].ly=now.b;
			next.a=now.a-(b-now.b), next.b=b;
			q.push(next);
		}
		else if ( now.a<=b-now.b && f[0][now.b+now.a].step==-1 ) {
			f[0][now.b+now.a].step=itm;
			f[0][now.b+now.a].op=5;
			f[0][now.b+now.a].lx=now.a, f[0][now.b+now.a].ly=now.b;
			next.a=0, next.b=now.a+now.b;
			q.push(next);
		}
		//第六种操作 
		if ( now.b>a-now.a && f[a][now.b-(a-now.a)].step==-1 ) {
			f[a][now.b-(a-now.a)].step=itm;
			f[a][now.b-(a-now.a)].op=6;
			f[a][now.b-(a-now.a)].lx=now.a, f[a][now.b-(a-now.a)].ly=now.b;
			next.a=a, next.b=now.b-(a-now.a);
			q.push(next);
		}
		else if ( now.b<=a-now.a && f[now.a+now.b][0].step==-1 ) {
			f[now.a+now.b][0].step=itm;
			f[now.a+now.b][0].op=6;
			f[now.a+now.b][0].lx=now.a, f[now.a+now.b][0].ly=now.b;
			next.a=now.a+now.b, next.b=0;
			q.push(next);
		}
	}
}

void init() {
	for(int i=0; i<=100; i++) {
		for(int j=0; j<=100; j++) {
			f[i][j].step=-1;
		}
	}
}

void print_path(int sa, int sb) {		//输出路径 
	if ( sa==0 && sb==0 ) return;
	print_path(f[sa][sb].lx,f[sa][sb].ly);
	//选择状态 
	choice(f[sa][sb].op);		 
}

void solve() {
	//int a,b,c;
	cin>>a>>b>>c;
	init();			//初始化 
	f[0][0].step=0;
	bfs(0,0);
	int cnt=inf;	//cnt用来记录最少次数 
	int sa,sb;
	
	//枚举任意一杯中水的容量为c的情况,寻找最少次数并记录其状态 
	for(int i=0; i<=a; i++ ) {
		if ( cnt>f[i][c].step && f[i][c].step!=-1 ) {
			cnt=f[i][c].step;
			sa=i, sb=c;
		}
	}
	for(int i=0; i<=b; i++) {
		if ( cnt>f[c][i].step && f[c][i].step!=-1 ) {
			cnt=f[c][i].step;
			sa=c, sb=i;
		}
	}
	//
	 
	if ( cnt==inf ) printf("impossible\n");
	else {
		printf("%d\n",cnt);
		//以dfs的形式输出路径 
		print_path(sa,sb);		
	}
}

int main() {
//	freopen("in.txt","r",stdin);
	solve();
	return 0;
}
发布了13 篇原创文章 · 获赞 6 · 访问量 576

猜你喜欢

转载自blog.csdn.net/zx1020354953/article/details/104571125