【解题报告】非常可乐(广度优先搜索入门题)


题意:给你3个杯子,容量分别为S,N,M,其中S=N+M,三个数都是正整数.一开始S是满的,N和M都是空的,杯子都没刻度.最少倒几次能使其中两个杯子平分可乐.

这道题是个BFS的入门题,解法很容易想到:

  • 杯子都没刻度,说明A杯往B杯倒可乐,只有2种情况:把B倒满,或者把A倒空,所以我们就可以得到2个新的状态,把它们加入广搜队列;当然A->B有6种排列方式,所以总共要写十二次倒可乐的状态转移操作.

  • 最少倒几次能使其中两个杯子平分可乐:也就是说第一次出现两个杯子的可乐量等于s/2时的操作次数.可以知道s % 2=1的话是肯定不可能有解的.

在此,主要用这个题练练STL:如何用STL方便地帮助搜索

注意:下面这种tuple、map的用法,在某些搜索的情景下是低效的,完全可以用struct和三维数组高效代替,此处只是练习STL

1. 表示当前可乐容量状态的三元组:

可以用含有三个元素的结构体存储状态,并且把它入队.STL里的tuple可以方便地存储一个多元组,这样就不用结构体啦:

定义一个三元组:

tuplehead;

获取该状态下的三个元素:

x=get<0>(head); y=get<1>(head); z=get<2>(head);

给这个组添加元素,比如s,0,0:

head=make_tuple(s,0,0);

2. 当前可乐容量状态对应的已经进行的倾倒次数:

自然而然想到map了

map,int>dist;

3. 某一状态是否已经被访问(搜索)过:

这个同上,其实完全可以用上面的dist代替:假如没被搜过,它对应的次数就是0啦

4.把map和tuple初始化为空,用.clear()函数就可以了

(tuple+map)AC代码
#include
using namespace std;
const int MAXN=100+5;
const int MAXM=0+5;
const int INF=0x3f3f3f3f;
int s,n,m;
queue >q;
map,int>dist;
tupletmp;
tuplehead;
bool daoman(int i,int j,int p) {
	return (i>=p-j)?1:0;
}
bool daokong(int i,int j,int p) {
	return (i+j<=p)?1:0;
}
void doit() {
	q.push(tmp);
	dist[tmp]=dist[head]+1;
}
void bfs() {
	head=make_tuple(s,0,0);
	q.push(head);
	int mn=INF;
	while(q.size()) {
		head=q.front();
		q.pop();
		int x=get<0>(head),y=get<1>(head),z=get<2>(head);
		if((x==s/2&&y==s/2)||(x==s/2&&z==s/2))mn=min(mn,dist[head]);
		if(mn!=INF) {
			cout<>s>>n>>m) {
		if(!s&&!n&&!m)break;
		while(q.size())q.pop();
		dist.clear();
		if(s%2)cout<<"NO"<<'\n';
		else bfs();
	}
	return 0;
}
(结构体+三维数组)AC代码
#include
using namespace std;
const int MAXN=100+5;
const int MAXM=0+5;
const int INF=0x3f3f3f3f;
int s,n,m;
int x,y,z;
int dist[MAXN][MAXN][MAXN];
struct node {
	int x,y,z;
} head,tmp;
queueq;
bool daoman(int i,int j,int p) {
	return (i>=p-j)?1:0;
}
bool daokong(int i,int j,int p) {
	return (i+j<=p)?1:0;
}
void doit(int xx,int yy,int zz) {
	if(dist[xx][yy][zz])return;
	tmp.x=xx,tmp.y=yy,tmp.z=zz;
	q.push(tmp);
	dist[xx][yy][zz]=dist[x][y][z]+1;
}
void bfs() {
	head.x=s,head.y=0,head.z=0;
	q.push(head);
	int mn=INF;
	while(q.size()) {
		head=q.front();
		q.pop();
		x=head.x,y=head.y,z=head.z;
		if((x==s/2&&y==s/2)||(x==s/2&&z==s/2))mn=min(mn,dist[x][y][z]);
		if(mn!=INF) {
			cout<>s>>n>>m) {
		if(!s&&!n&&!m)break;
		memset(dist,0,sizeof(dist));
		while(q.size())q.pop();
		if(s%2)cout<<"NO"<<'\n';
		else bfs();
	}
	return 0;
}