4.29 记录 机器分配

这篇博客讨论了一道来自洛谷P2066的动态规划题目,涉及如何在给定公司和机器数量的情况下,最大化利润。博主通过定义dp和b数组来存储状态,并采用字典序的方式输出最优分配方案。代码中展示了如何递归回溯找到最优解,并给出了测试数据。

(题目来源 洛谷 P2066)
这题基本上来讲DP没什么很大的难度。
记dp[i][j]表示前i个公司分j台机器会得到的最大利润,那么就有:
dp[i][j] = max(dp[i][j],dp[i][j - k] + a[i][k]) (0 <= k <= j).
这题小难点还是在输出这个分配方案上。根据我们已有的经验,首先我们必须准确的知道到底是何种方案是最佳的,并且存储这个状态;其次我们要把推出方案的路径存起来。
加上一个b[i][j],表示前i个公司用了j台机器获得总利润最大时,前(i-1)个公司应该分得的机器总数(这个思路来源于我们的递推式)。
这样一来,当dp[i][j]<dp[i][j - k] + a[i][k]时,b[i][j]=j-k.这样一来问题就解决了。
(PS:这题没有spj,输出是按字典序的,也就是靠后的公司用的机器尽可能多。这样一来,枚举k的时候要从j向0处理。或者可以把判断改成<=,这样一来更新的时候存的方案就是优先存用机器多的方案。最后用的多会优先,所以也可以形成字典序)
代码(附赠字典序测试数据一组):

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int go,dp[21][21],a[21][21],b[21][21];
void bye(int n,int m){
	int temp;
	if(n == 0) return;
	bye(n - 1,b[n][m]);
	printf("%d %d\n",n,m - b[n][m]);
}
int main(){
	int i,j,k,n,m;
	scanf("%d %d",&n,&m);
	for(i = 1;i <= n;i++){
		for(j = 1;j <= m;j++){
			scanf("%d",&a[i][j]);
		}
	} 
	for(i = 1;i <= n;i++){
		for(j = 1;j <= m;j++){
			for(k = j;k >= 0;k--){
				if(dp[i - 1][j - k] + a[i][k] > dp[i][j]){
					dp[i][j] = dp[i - 1][j - k] + a[i][k];
					b[i][j] = j - k;
					if(i == n) go = k;
				}
			}
		}
	}
	printf("%d\n",dp[n][m]);
	bye(n,m);
	return 0;
}
/*
2 5
1 1 1 1 1
1 1 1 1 2

.out:
2
1 0
2 5
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值