仓库守卫 Storage Keepers

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

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

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

2. 求此时的最小花费

定义
d p [ i ] [ j ] dp[i][j] dp[i][j]为考虑前 i i i个人看守前 j j j个仓库并满足求出的安全指数条件的最小花费
初始化
d p [ 0 ] [ i ] = i n f dp[0][i]=inf 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]) if(SafetyIndex[i]/(jx)>=)dp[i][j]=min(dp[i][j],dp[i1][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] dp[i]都只用到 d p [ i − 1 ] dp[i-1] dp[i1],所以可以滚动优化降一维,过了那就算了吧233333。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值