仓库守卫 Storage Keepers

在这里插入图片描述
UVA10163
这道题需要两次dp

1. 求最小安全指数最大值

定义
d p [ i ] [ j ] dp[i][j] 为考虑前i个人看守前j个仓库最小安全指数最大值, S a f e t y I n d e x [ i ] SafetyIndex[i] 为第 i i 个人的能力值。
初始化
d p [ i ] [ 0 ] = i n f dp[i][0]=inf (常数/0=无穷大)
剩下的 d p = 0 dp=0
转移方程
d p [ i ] [ j ] = m a x ( d p [ i ] [ j ] , m i n ( d p [ i 1 ] [ x ] , S a f e t y I n d e x [ i ] / ( j x ) ) ) , ( 0 x < j ) dp[i][j]=max(dp[i][j], min(dp[i - 1][x], SafetyIndex[i] / (j - x))),(0\leq x<j)
其中 x x 为前 i i 个人看守前 x x 个仓库,而剩下的 j x j-x 个仓库由第 i i 个人看守。
这样, d p [ M ] [ N ] dp[M][N] 就是所求答案。

2. 求此时的最小花费

定义
d p [ i ] [ j ] dp[i][j] 为考虑前 i i 个人看守前 j j 个仓库并满足求出的安全指数条件的最小花费
初始化
d p [ 0 ] [ i ] = i n f dp[0][i]=inf
剩下的dp元素=0
转移方程
i f ( S a f e t y I n d e x [ i ] / ( j x ) > = ) d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ i 1 ] [ x ] + S a f e t y I n d e x [ i ] ) if(SafetyIndex[i] / (j - x) >= 上一问求出的结果)\\dp[i][j] = min(dp[i][j], dp[i - 1][x] + SafetyIndex[i])

AC代码

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
constexpr static int inf = 0x3f3f3f3f;
int N, M;
int SafetyIndex[31];
int dp[31][101];
//考虑前i个人看守前j个仓库最小安全指数最大值
bool Input() {
	cin >> N >> M;
	if (!N && !M) {
		return false;
	}
	for (int i = 1; i <= M; ++i) {
		cin >> SafetyIndex[i];
	}
	return true;
}
void DP() {
	//第一次dp
	for (int i = 0; i <= M; ++i) {
		dp[i][0] = inf;
	}
	for (int i = 1; i <= M; ++i) {
		for (int j = 1; j <= N; ++j) {
			dp[i][j] = dp[i - 1][j];
			for (int x = 0; x < j; ++x) {
				dp[i][j] = max(dp[i][j], min(dp[i - 1][x], SafetyIndex[i] / (j - x)));
			}
		}
	}
	int Min = dp[M][N];
	cout << Min << ' ';
	//如果安全指数为0,则谁都不雇佣最便宜
	if (!Min) {
		cout << 0 << endl;
		return;
	}
	//第二次dp
	memset(dp, 0x0, sizeof(dp));
	for (int i = 1; i <= N; i++) { 
		dp[0][i] = inf;
	}
	for (int i = 1; i <= M; ++i) {
		for (int j = 1; j <= N; ++j) {
			dp[i][j] = dp[i - 1][j];
			for (int x = 0; x < j; ++x) {
				if (SafetyIndex[i] / (j - x) >= Min) {
					dp[i][j] = min(dp[i][j], dp[i - 1][x] + SafetyIndex[i]);
				}
			}
		}
	}
	
	cout << dp[M][N] << endl;
}
int main() {
	while (Input()) {
		memset(dp, 0x0, sizeof(dp));
		DP();
	}
	return 0;
}

每次的 d p [ i ] dp[i] 都只用到 d p [ i 1 ] dp[i-1] ,所以可以滚动优化降一维,过了那就算了吧233333。

发布了35 篇原创文章 · 获赞 38 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42971794/article/details/104070636