acw 倒水问题(爆搜出所有方案)

题目链接

题目
有三个杯子,容量分别为 A , B , C A,B,C A,B,C
初始时, C C C 杯装满了水,而 A , B A,B A,B 杯都是空的。
现在在保证不会有漏水的情况下进行若干次如下操作:
将一个杯子 x x x 中的水倒到另一个杯子 y y y 中,当 x x x 空了或者 y y y 满了时就停止(满足其中一个条件才停下)。
请问,在操作全部结束后, C C C 中的水量有多少种可能性。

0 ≤ A , B , C ≤ 4000 0≤A,B,C≤4000 0A,B,C4000

思路
一开始觉得是思维题,想了一会没有思路。
一看标签是bfs/dfs 和 哈希,就想起来是像去年沈阳站那道 bfs 一样,爆搜出所有方案。

bfs, dfs 两种方式。

细节:
映射这三个数有三种方式:

  1. 放到结构体中,map映射结构体。但是需要在结构体中重载运算符,所有元素都要比较。
  2. 放到vector中,map映射vector。时间复杂度较高,前几天cf有人这样写被hack超时了,这题也超时。
  3. 将这三个数哈希成一个数,map映射这个数。如果三个数比较小的话,可以选择一个比较大的数作为哈希值;否则或者找一个冲突概率小的数。复杂度较优。

执行操作的方式:
一共三个数,两两之间操作,可以直接ifelse,也可以把三个数存到数组中,二重循环遍历操作。
可以直接把数组传给函数处理操作,函数中修改数组后原数组也改变。

Code
bfs,map映射结构体,ifelse处理操作:

#include<bits/stdc++.h>
using namespace std;

#define Ios ios::sync_with_stdio(false),cin.tie(0)
#define mem(a,b) memset(a,b,sizeof a)

const int N = 200010, mod = 1e9+7;
int T, n, m;
int va, vb, vc;

struct node{
	int a, b, c;
	
	friend bool operator < (node a, node b){
		if(a.a!=b.a) return a.a < b.a;
		else if(a.b!=b.b) return a.b < b.b;
		else return a.c < b.c;
	}
};

map<node, bool> f;
map<int, int> mp;

void bfs()
{
	mp.clear();
	f.clear();
	
	queue<node> que;
	que.push({0, 0, vc});
	f[{0, 0, vc}] = 1;
	
	while(que.size())
	{
		int a = que.front().a, b = que.front().b, c = que.front().c;
		que.pop();
		
		mp[c] = 1;
		if(a)
		{
			int ta = a, tb = b, tc = c;
			if(ta <= vb-tb){
				tb += ta;
				ta = 0;
			}else{
				ta -= vb-tb;
				tb = vb;
			}
			if(!f.count({ta, tb, tc})) f[{ta, tb, tc}] = 1, que.push({ta, tb, tc});
			
			ta = a, tb = b, tc = c;
			if(ta <= vc-tc){
				tc += ta;
				ta = 0;
			}else{
				ta -= vc-tc;
				tc = vc;
			}
			if(!f.count({ta, tb, tc})) f[{ta, tb, tc}] = 1, que.push({ta, tb, tc});
		}
		if(b)
		{
			int ta = a, tb = b, tc = c;
			if(tb <= va-ta){
				ta += tb;
				tb = 0;
			}else{
				tb -= va-ta;
				ta = va;
			}
			if(!f.count({ta, tb, tc})) f[{ta, tb, tc}] = 1, que.push({ta, tb, tc});
			
			ta = a, tb = b, tc = c;
			if(tb <= vc-tc){
				tc += tb;
				tb = 0;
			}else{
				tb -= vc-tc;
				tc = vc;
			}
			if(!f.count({ta, tb, tc})) f[{ta, tb, tc}] = 1, que.push({ta, tb, tc});
		}
		if(c)
		{
			int ta = a, tb = b, tc = c;
			if(tc <= va-ta){
				ta += tc;
				tc = 0;
			}else{
				tc -= va-ta;
				ta = va;
			}
			if(!f.count({ta, tb, tc})) f[{ta, tb, tc}] = 1, que.push({ta, tb, tc});
			
			ta = a, tb = b, tc = c;
			if(tc <= vb-tb){
				tb += tc;
				tc = 0;
			}else{
				tc -= vb-tb;
				tb = vb;
			}
			if(!f.count({ta, tb, tc})) f[{ta, tb, tc}] = 1, que.push({ta, tb, tc});
		}
	}
}

signed main(){
	Ios;
	while(cin >> va >> vb >> vc)
	{
		bfs();
		cout << mp.size() << endl;
	}
	
	return 0;
}

dfs,map映射哈希值,数组遍历处理操作:

#include<bits/stdc++.h>
using namespace std;

#define Ios ios::sync_with_stdio(false),cin.tie(0)
#define mem(a,b) memset(a,b,sizeof a)
#define int long long
#define PII pair<int,int>
#define pb push_back
#define fi first
#define se second
#define endl '\n'

/**/

const int N = 200010, mod = 1e9+7;
int T, n, m;
int c[3], v[3];

map<int, bool> f;
map<int, bool> mp;

int get(int c[])
{
	return c[0]*5000*5000 + c[1]*5000 + c[2];
}

void pour(int c[], int x, int y)
{
	if(c[x] >= v[y]-c[y])
	{
		c[x] -= v[y]-c[y];
		c[y] = v[y];
	}
	else{
		c[y] += c[x];
		c[x] = 0;
	}
}

void dfs(int c[])
{
	int t[3];
	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++)
		{
			if(i==j) continue;
			memcpy(t, c, sizeof t);
			pour(t, i, j);
			
			if(f.count(get(t))) continue;
			f[get(t)] = 1;
			mp[t[2]] = 1;
			dfs(t);
		}
}

signed main(){
	Ios;
	while(cin >> v[0] >> v[1] >> v[2])
	{
		c[0] = c[1] = 0, c[2] = v[2];
		
		f.clear();
		mp.clear();
		
		f[get(c)] = 1;
		mp[c[2]] = 1;
		
		dfs(c);
		cout << mp.size() << endl;
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值