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

被折叠的 条评论
为什么被折叠?



