UVA 10603:倒水

3 篇文章 0 订阅

题目:https://vjudge.net/problem/UVA-10603

需要注意的是:同一状态可以多次得到,但是到水量可能不同。有两种方法处理:

1.在每次判断当前状态是否存在时,判断当前状态即使存在,倒水量是否更小

2.用优先队列,每次先转移到水量较少的状态。

#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#include<math.h>
#include<string>
#include<string.h>
#include<map>
#include<unordered_map>
#include<unordered_set>
#include<set>
#include<stack>
#include<sstream>
using namespace std;

const int maxn = 205;
int a, b, c, d, d1, summin, summin1, ok;
int vis[maxn][maxn], litre[3];
struct node {
	int w[3],sum;
	bool operator < (const node & nd) const{
		return sum  > nd.sum;
	}
};
void bfs() {
	priority_queue<node> q;
	q.push(node({ 0,0,c ,0 }));
	vis[0][0] = 1;
	while (!q.empty()) {	
		node nd = q.top();
		q.pop();
		if (nd.w[0] == d || nd.w[1] == d || nd.w[2] == d)
		{
			ok = 1;
			summin = min(summin, nd.sum);
			break;
		}
		for (int i = 0; i < 3; i++)
			if (nd.w[i] >= d1 && nd.w[i] < d)
			{
				if (nd.w[i] == d1)
				{
					summin1 = min(summin1, nd.sum);
				}
				else
				{
					d1 = nd.w[i];
					summin1 = nd.sum;
				}
			}
		node temp;
		for (int i = 0; i < 3; i++) 
		{	
			if (nd.w[i] > 0) 
			{
				for (int j = 0; j < 3; j++)
				{
					temp = nd;
					if (j != i && nd.w[j]!=litre[j]) 
					{
						if (nd.w[i] >= litre[j] - nd.w[j] )
						{
							temp.w[i] = nd.w[i] - (litre[j] - nd.w[j]);
							temp.w[j] = litre[j];	
							temp.sum += litre[j] - nd.w[j];
						}
						else
						{
							temp.w[i] = 0;
							temp.w[j] = nd.w[j] + nd.w[i];
							temp.sum += nd.w[i];
						}
						if (!vis[temp.w[0]][temp.w[1]])
						{
							q.push(temp);
							vis[temp.w[0]][temp.w[1]] = 1;
						}
					}		
				}
			}
		}
	}

}


int main() {
	int t;
	cin >> t;
	while (t--) {
		cin >> a >> b >> c >> d;
		litre[0] = a; litre[1] = b; litre[2] = c;
		summin = summin1 = 0x3f3f3f3f;
		ok = d1 = 0;
		memset(vis, 0, sizeof(vis));
		bfs();
		if (ok)
			cout << summin << " " << d << endl;
		else
			cout << summin1 << " " << d1 << endl;	 
	}
	return 0;
}

DFS:

#include<iostream>
#include<limits.h>
#include<algorithm>
#include<string.h>
using namespace std;

//v表示容器的毫升,st表示各容器每次注水状态
int st[3], v[3], vis[201][201][201];
//a,b,c表示容器的毫升,d1表示目前最接近d的毫升数
int a, b, c, d, d1;
int flag, ans0, ans1;


void dfs(int sumv)
{
	if (count(st, st + 3, d))
	{
		if(sumv < ans0)
			ans0 = sumv;
		flag = 1;
		return;
	}
	if (flag && sumv >= ans0)
		return;
	if (!flag)//若达不到d,则找一个最接近d的注水量,并记录最小注水
	{
		for (int i = 0; i < 3; i++)
		{
			if (st[i] < d && st[i] >= d1)
			{
				if (d1 == st[i])
					ans1 = min(ans1, sumv);
				else
				{
					d1 = st[i];
					ans1 = sumv;
				}		
			}
		}
	}
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			if (i != j && st[i] && st[j] != v[j]) //由i倒入j,i不空且j不满
			{
				//tmp系列参数用于后面的回溯
				int tmp_i = st[i];
				int tmp_j = st[j];
				int tmp_v;
				if (st[i] + st[j] < v[j])
				{
					tmp_v = st[i];
					st[j] = st[i] + st[j];
					st[i] = 0;
				}
				else
				{
					tmp_v = v[j] - st[j];
					st[i] = st[i] - tmp_v;
					st[j] = v[j];
				}
				if (!vis[st[0]][st[1]][st[2]])
				{
					vis[st[0]][st[1]][st[2]] = 1;
					dfs(sumv + tmp_v);
					vis[st[0]][st[1]][st[2]] = 0;
				}
				st[i] = tmp_i;
				st[j] = tmp_j;
			}
		}
	}
	return;
}

int main()
{
	int num;
	cin >> num;
	while (num--)
	{
		flag = 0;
		d1 = 0;
		ans0 = ans1 = INT_MAX;
		memset(vis, 0, sizeof(vis));
		cin >> a >> b >> c >> d;
		v[0] = a; v[1] = b; v[2] = c;
		st[0] = 0; st[1] = 0; st[2] = c;
		vis[0][0][c] = 1;
		dfs(0);
		flag == 1 ? (cout << ans0 << " " << d << endl): (cout << ans1 << " " << d1 << endl);
	}		
}
//56 184 180 16

 

BFS: 

#include<iostream>
#include<queue>
#include<string.h>
using namespace std;

struct state 
{
	int water[3];
	int sumv;
}st, st1;

queue<state> q;
int d;
int v[3], minvolume[201], vis[201][201]; //不必用三维vis,因为已知前2个元素不同,第3个必不同

void cmp(state st1) 
{
	for (int k = 0; k < 3; k++)
	{
		if (minvolume[st1.water[k]] < 0)
			minvolume[st1.water[k]] = st1.sumv;
		else
			minvolume[st1.water[k]] = minvolume[st1.water[k]] > st1.sumv ? st1.sumv : minvolume[st1.water[k]];
	}
}
void bfs() 
{
	q.push(st);
	while (!q.empty()) 
	{
		st = q.front();
		q.pop();
		for (int i = 0; i < 3; i++)
		{
			for (int j = 0; j < 3; j++)
			{
				if (i == j)
					continue;
				st1 = st;
				//i杯倒入j杯,若i杯水量小于j杯剩余水量,倒水量为st.water[i]
				//            若i杯水量小于j杯剩余水量,倒水量为w[j] - st.water[j]
				int curv = v[j] - st.water[j] > st.water[i] ? st.water[i] : v[j] - st.water[j];
				st1.water[i] -= curv;
				st1.water[j] += curv;
				//如果此次水量与之前不同|| 现在3个杯中容量所需的倒水量小于minvolume中记录
				if (!vis[st1.water[0]][st1.water[1]] || minvolume[st1.water[0]] > (st.sumv + curv) || minvolume[st1.water[1]] > (st.sumv + curv) || minvolume[st1.water[2]] > (st.sumv + curv))
				{
					vis[st1.water[0]][st1.water[1]] = 1;
					st1.sumv = st.sumv + curv;
					cmp(st1);
					q.push(st1);
				}
			}
		}
	}
}

int main()
{
	int num;
	cin >> num;
	while (num--) 
	{
		cin >> v[0] >> v[1] >> v[2] >> d;
		memset(vis, 0, sizeof(vis));
		memset(minvolume, -1, sizeof(minvolume));
		st.water[0] = 0;
		st.water[1] = 0;
		st.water[2] = v[2];
		st.sumv = 0;
		minvolume[0] = minvolume[st.water[2]] = 0;
		vis[0][0] = 1;
		bfs();
		for (int i = d; i >= 0; i--) {
			if (minvolume[i] >= 0) {
				cout << minvolume[i] << " " << i << endl;
				break;
			}
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值