uva10163(DP)

该博客主要讨论了如何使用动态规划(DP)解决UVA10163问题。问题背景是分配m个能力不同的保安到n个仓库,以最大化仓库的整体安全系数L,同时要求最小化总工资Y。博主通过建立两个动态规划状态转移方程,分别用于计算最大安全系数和最小总工资,并提供了AC(Accepted)代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

有n个仓库,现在要请m个保安来看守.

每个保安有个能力值Pi,Pi值为多少,这个保安最多就能看守多少个仓库.同时也是聘请这个保安的工资.

如果这个保安看守k个仓库,那么每个仓库的安全系数就是Pi / k (整除);如果一个仓库没有保安看守,那么安全系数就是0;总安全系数L 就是所有仓库中安全系数最低的那个仓库的值.

现在我们要求L最大是多少,并且求L最大情况下,最小的工资Y;


思路:

这题可以用两个dp来解,第一个求L,第二个求Y;


首先我们要先求L,

f[i][j]表示前i个保安,看守前j个仓库,最小的安全系数 最大是多少;

我们可以用到一个状态转移

f[cur][l] = max(f[cur][l] , min(dp(cur - 1 , l - i) , p[cur] / i)); // (i <= l)
min(dp(cur  - 1 , l - i) , p[cur] / i )表示当前这个保安看守i个仓库,(那么这个保安看守的仓库的安全值就是p[cur] / i) 和之前的cur - 1个保安看守l - i个仓库的安全系数取小值.

并且在所有小值中取最大值.

这样就得到了最大的安全系数.


在知道安全系数的情况下,我们再来求最小工资.

f2[i][j]表示前i个保安,看守前j个仓库(所有安全系数都满足条件 >L),最小工资是多少.

f2[cur][l] = min(f2[cur][l] , dp2(cur - 1 , l - i) + p[cur]); // i <= l && p[cur] / i >= L


AC代码:


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 105;
const int M = 35;
int n,m,L, Y ,p[N];
int f[M][N];
int f2[M][N];

int dp(int cur , int l) {
	if(cur == 0) {
		if(l > 0)
			return 0;
		return INF;
	}
	if(l == 0) {
		return INF;
	}
	if(f[cur][l] != -1)
		return f[cur][l];
	f[cur][l] = dp(cur - 1 , l);
	for(int i = 1 ; i <= p[cur] ; i++) {
		if(i <= l)
			f[cur][l] = max(f[cur][l] , min(dp(cur - 1 , l - i) , p[cur] / i));
	}
	return f[cur][l];
}
int dp2(int cur , int l) {
	if(cur == 0) {
		if(l > 0)
			return INF;
		return 0;
	}
	if(l == 0)
		return 0;
	if(f2[cur][l] != -1)
		return f2[cur][l];
	f2[cur][l] = dp2(cur - 1 , l);
	for(int i =1 ; i <= p[cur] ; i++) {
		if(i <= l && p[cur] / i >= L)
			f2[cur][l] = min(f2[cur][l] , dp2(cur - 1 , l - i) + p[cur]);
	}
	return f2[cur][l];
}
int main() {
	while(scanf("%d%d",&n,&m) && n) {
		memset(f, -1 ,sizeof(f));
		memset(f2, -1 ,sizeof(f2));
		for(int i = 1 ; i <= m ;i++) {
			scanf("%d",&p[i]);
		}
		L = dp(m,n);
		if(L != 0)
			Y = dp2(m,n);
		else
			Y = 0;
		printf("%d %d\n",L, Y);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值