动态规划:倒水问题

倒水问题

问题描述

邓老师有有 2 个容量分别为 n 单位、m 单位的没有刻度的杯子。初始,它们都是空的。邓老师给了你 t 分钟时间。每一分钟,他都可以做下面 4 件事中的任意一件:

  1. 用水龙头装满一个杯子。
  2. 倒空一个杯子。
  3. 把一个杯子里的水倒到另一个杯子里,直到一个杯子空了或者另一个杯子满了。
  4. 什么都不做。

邓老师希望最后能获得 d 个单位的水,假设最后两个杯具中水量的总和为 x,那么邓老师的不满意度就为 |d-x|。
你希望邓老师尽可能地满意,于是请你计算邓老师的不满意度最小是多少。

输入格式

一行 4 个整数 n,m,t,d,分别表示两个杯具的容量、时间限制、以及邓老师的期望值。

输出格式

一行一个整数,表示邓老师最小的不满意度。

样例输入

7 25 2 16

样例输出

9

样例解释

你可以在第 1 分钟用水龙头装满任意一个杯子,并在第 2 分钟什么都不做,即可让邓老师的不满意度为 9。可以证明不存在更优的解。

代码实现

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

// ================= 代码实现开始 =================

/* 请在这里定义你需要的全局变量 */
typedef pair<int,int> pii;
const int N = 2003;

// mind: mind[i][j]表示从初始状态到(i,j)需要的最少步数
// q: 模拟队列
// qh: 队头下标
// qt: 队尾下标
int mind[N][N];
pii q[N*N];
int qh, qt;

// 模拟倒水操作:
// p:当前状态
// k:操作码
// n:A杯容量
// m:B杯容量
// 返回值:操作之后的状态
pii to(pii p, int k, int n, int m){
	switch(k){
		case 0://倒空A
		    return pii(0, p.second);
	    case 1://倒空B
		    return pii(p.first, 0);
	    case 2://倒满A
		    return pii(n, p.second);
	    case 3://倒满B
		    return pii(p.second, m);
	    case 4://B倒入A:现有水量all=p.first+p.second, 若n<all, 则A杯必满, B杯=all-n; 若all<n, 则B杯必空, A杯=all
	        return pii(min(p.first + p.second, n), max(p.first + p.second - n, 0));
		case 5://A倒入B:上述反向情况
		    return pii(max(p.first + p.second - n, 0), min(p.first + p.second, n));
	    default://无操作
		    return p;
	}
		
}


// 计算答案的函数
// n, m, t, d:意义均与题目描述一致
// 返回值:即为答案
int getAnswer(int n, int m, int t, int d) {
    /* 请在这里设计你的算法 */
	memset(mind, -1, sizeof(mind));
	qh = qt = 0;
	q[++qt] = pii(0,0);//初始状态
	mind[0][0] = 0;
	
	// BFS
	while(qh < qt){
		pii u = q[++qh];
		if(mind[u.first][u.second] == t)
			break;//已经进行t步
		for(int k=0; k<6; ++k){//忽略无操作
			pii v = to(u, k, n, m);
			if(mind[v.first][v.second] != -1)
				continue;//判断该状态是否已经到达过
			q[++qt] = v;
			mind[v.first][v.second] = mind[u.first][u.second] + 1;//v是由u前进1步达到的状态
		}
	}
	
	int ans = d;
	for(int i=0; i<=n; ++i)
		for(int j=0; j<=m; ++j)
			if(mind[i][j] != -1)
				ans = min(ans, mind[i][j]);
			
	return ans;
}

// ================= 代码实现结束 =================

int main() {
    int n, m, t, d;
    scanf("%d%d%d%d", &n, &m, &t, &d);
    int ans = getAnswer(n, m, t, d);
    printf("%d\n", ans);
    return 0;
}

来源

来自邓俊辉老师的《算法训练营》第一期。

猜你喜欢

转载自blog.csdn.net/EasonDongH/article/details/85049899
今日推荐