uva 10603 Fill code2

题目:Fill


题意:有3个容积为a,b,c的杯子,最初a、b为空,c中装满水。每次可以从一个杯子向另一个杯子倒水,但只有把一个杯子倒空或把另一个杯子倒满时才能停止。如果要使其中一个杯子中有d升水,求最少倒水的的体积。若无法满足 ,则目标水量要比d小且和d尽量接近。


思路:

同书上思路,用priority_queue代替queue,比用队列快。

详见对刘汝佳代码的注释。

思路1见:uva 10603 Fill


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
#include<deque>
#include<queue>
#include<algorithm>
#include<sstream>
using namespace std;

#define n 3
#define m 205

struct Node {
	int x[n];
	int step;
	Node() {}
	Node(Node y[],int s) {
		memcpy(x,y,sizeof(x));
		step=s;
	}
	Node(int one,int two,int three,int s) {
		x[0]=one,x[1]=two,x[2]=three,step=s;
	}
	bool operator <(const Node& other) const {
		if(step>other.step) return true;
		if(step<other.step) return false;
		for(int i=0; i<n; i++) {
			if(x[i]<other.x[i]) return true;
			if(x[i]>other.x[i]) return false;
		}
		return false;
	}
};

int d;
Node M;
bool use[m][m];
int ans[m],dis[m][m];

void init() {
	memset(use,0,sizeof(use));
	memset(ans,-1,sizeof(ans));
	memset(dis,-1,sizeof(dis));
}

void bfs(Node IN) {
	priority_queue<Node> que;
	que.push(IN);
	dis[IN.x[0]][IN.x[1]]=0;
	while(!que.empty()) {
		Node head=que.top();
		que.pop();
		if(use[head.x[0]][head.x[1]]) continue;
		use[head.x[0]][head.x[1]]=true;
		for(int i=0; i<n; i++)
			if(ans[head.x[i]]==-1||ans[head.x[i]]>head.step) ans[head.x[i]]=head.step;
		if(ans[d]!=-1) break;
		for(int i=0; i<n; i++) {
			for(int j=0; j<n; j++) {
				if(i!=j&&head.x[i]!=0&&head.x[j]!=M.x[j]) {
					Node ch=head;
					int move;
					if(ch.x[i]>=M.x[j]-ch.x[j]) move=M.x[j]-ch.x[j];
					else move=ch.x[i];
					ch.x[i]-=move,ch.x[j]+=move,ch.step+=move;
					if((dis[ch.x[0]][ch.x[1]]==-1||ch.step<dis[ch.x[0]][ch.x[1]])) {
						dis[ch.x[0]][ch.x[1]]=ch.step;
						que.push(ch);
					}
				}
			}
		}
	}
	int now=d;
	while(now>=0) {
		if(ans[now]>=0){
			printf("%d %d\n",ans[now],now);
			return ;
		}
		now--;
	}
}

int main() {
	int T;
	scanf("%d",&T);
	while(T--) {
		int A,B,C;
		scanf("%d%d%d%d",&A,&B,&C,&d);
		M=Node(A,B,C,0);
		init();
		bfs(Node(0,0,C,0));
	}
	return 0;
}



刘汝佳的代码+注释:

// UVa10603 Fill
// Rujia Liu
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;

struct Node {
	int v[3], dist;	//v[]: 水量  dist:路径 
	bool operator < (const Node& rhs) const {
		return dist > rhs.dist;
	}
};

const int maxn = 200 + 5;
int mark[maxn][maxn], dist[maxn][maxn], cap[3], ans[maxn];
//mark[][]: 是否已有这种状态  dist[][]: 杯0中有i升水、1中有j升水时的d'  cap[]: 杯子的容量  ans[]: d(d')为i时的最少水量 

void update_ans(const Node& u) {	//计算ans 
	for(int i = 0; i < 3; i++) {
		int d = u.v[i];
		if(ans[d] < 0 || u.dist < ans[d]) ans[d] = u.dist;
	}
}

void solve(int a, int b, int c, int d) {	//bfs 
	cap[0] = a;
	cap[1] = b;
	cap[2] = c;
	memset(ans, -1, sizeof(ans));
	memset(mark, 0, sizeof(mark));
	memset(dist, -1, sizeof(dist));
	priority_queue<Node> q;	//队列 

	Node start;	//初始状态 
	start.dist = 0;
	start.v[0] = 0;
	start.v[1] = 0;
	start.v[2] = c;
	q.push(start);

	dist[0][0] = 0;
	while(!q.empty()) {
		Node u = q.top();
		q.pop();
		if(mark[u.v[0]][u.v[1]]) continue;	//使用过 
		mark[u.v[0]][u.v[1]] = 1;
		update_ans(u);
		if(ans[d] >= 0) break;	//符合条件 
		for(int i = 0; i < 3; i++)	//从杯i倒到杯j 
			for(int j = 0; j < 3; j++) 
				if(i != j) {
					if(u.v[i] == 0 || u.v[j] == cap[j]) continue;	//j中水满或i中无水 
					int amount = min(cap[j], u.v[i] + u.v[j]) - u.v[j];	//倒的水量 
					Node u2;
					memcpy(&u2, &u, sizeof(u));
					u2.dist = u.dist + amount;	//倒水 
					u2.v[i] -= amount;
					u2.v[j] += amount;
					int& D = dist[u2.v[0]][u2.v[1]];
					if(D < 0 || u2.dist < D) {	//加入队列 
						D = u2.dist;
						q.push(u2);
					}
				}
	}
	while(d >= 0) {	//输出 
		if(ans[d] >= 0) {
			printf("%d %d\n", ans[d], d);
			return;
		}
		d--;
	}
}

int main() {
	int T, a, b, c, d;
	scanf("%d", &T);
	while(T--) {	//输入 
		scanf("%d%d%d%d", &a, &b, &c, &d);
		solve(a, b, c, d);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值