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

题意:给你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可以方便地存储一个多元组,这样就不用结构体啦:

定义一个三元组:

tuple<int,int,int>head;

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

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

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

head=make_tuple(s,0,0);

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

自然而然想到map了

map<tuple<int,int,int>,int>dist;

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

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

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

(tuple+map)AC代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN=100+5;
const int MAXM=0+5;
const int INF=0x3f3f3f3f;
int s,n,m;
queue<tuple<int,int,int> >q;
map<tuple<int,int,int>,int>dist;
tuple<int,int,int>tmp;
tuple<int,int,int>head;
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<<mn<<'\n';
			break;
		}
		if(daoman(x,y,n)) {
			tmp=make_tuple(x-(n-y),n,z);
			if(!dist[tmp]) doit();
		}
		if(daoman(x,z,m)) {
			tmp=make_tuple(x-(m-z),y,m);
			if(!dist[tmp]) doit();
		}
		if(daoman(y,z,m)) {
			tmp=make_tuple(x,y-(m-z),m);
			if(!dist[tmp]) doit();
		}
		if(daoman(y,x,s)) {
			tmp=make_tuple(s,y-(s-x),z);
			if(!dist[tmp])doit();
		}
		if(daoman(z,x,s)) {
			tmp=make_tuple(s,y,z-(s-x));
			if(!dist[tmp]) doit();
		}
		if(daoman(z,y,n)) {
			tmp=make_tuple(x,n,z-(n-y));
			if(!dist[tmp]) doit();
		}
		if(daokong(x,y,n)) {
			tmp=make_tuple(0,x+y,z);
			if(!dist[tmp]) doit();
		}
		if(daokong(x,z,m)) {
			tmp=make_tuple(0,y,x+z);
			if(!dist[tmp])doit();
		}
		if(daokong(y,z,m)) {
			tmp=make_tuple(x,0,y+z);
			if(!dist[tmp]) doit();
		}
		if(daokong(y,x,s)) {
			tmp=make_tuple(x+y,0,z);
			if(!dist[tmp]) doit();
		}
		if(daokong(z,x,s)) {
			tmp=make_tuple(x+z,y,0);
			if(!dist[tmp]) doit();
		}
		if(daokong(z,y,n)) {
			tmp=make_tuple(x,y+z,0);
			if(!dist[tmp]) doit();
		}
	}
	if(mn==INF)cout<<"NO"<<'\n';
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	while(cin>>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<bits/stdc++.h>
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;
queue<struct node>q;
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<<mn<<'\n';
			break;
		}
		if(daoman(x,y,n))doit(x-(n-y),n,z);
		if(daoman(x,z,m))doit(x-(m-z),y,m);
		if(daoman(y,z,m))doit(x,y-(m-z),m);
		if(daoman(y,x,s))doit(s,y-(s-x),z);
		if(daoman(z,x,s))doit(s,y,z-(s-x));
		if(daoman(z,y,n))doit(x,n,z-(n-y));
		if(daokong(x,y,n))doit(0,x+y,z);
		if(daokong(x,z,m))doit(0,y,x+z);
		if(daokong(y,z,m))doit(x,0,y+z);
		if(daokong(y,x,s))doit(x+y,0,z);
		if(daokong(z,x,s))doit(x+z,y,0);
		if(daokong(z,y,n))doit(x,y+z,0);
	}
	if(mn==INF)cout<<"NO"<<'\n';
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	while(cin>>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;
}
posted @ 2022-01-19 09:35  yige_2019  阅读(72)  评论(0编辑  收藏  举报
/**/