【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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章