1 条题解
-
0
自动搬运
来自洛谷,原作者为

冈崎梦美
**搬运于
2025-08-24 21:33:35,当前版本为作者最后更新于2017-12-20 23:47:15,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
一道经典的区间DP练习题。
设f[i][j]为前i个公司总共分配j台机器的最大利润。对于第i家子公司,我们可以给其分配的机器台数为:
0,1,2……m所以在该区间内枚举一个值k,状态转移方程即为:
f[i][j]=max(f[i-1][j-k],f[i][j]);那么,如何处理方案输出问题呢?
我们设
path[i][j][h]对于前i个公司共分配j台机器的最优方案,第h个公司应分配多少台机器,当状态发生转移时,更新path数组即可。最终的答案就存放在path[n][m][i]之中。贴代码:
#include<bits/stdc++.h> using namespace std; int f[11][16],graph[11][16],path[11][16][11],n,m; int main() { cin>>n>>m; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) cin>>graph[i][j]; } memset(f,0,sizeof(f)); for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) for(int k=0;k<=j;k++) { if (f[i][j]<f[i-1][j-k]+graph[i][k]) { f[i][j]=f[i-1][j-k]+graph[i][k]; for(int h=1;h<i;h++) path[i][j][h]=path[i-1][j-k][h];//path数组只有在状态发生转移时才更新 path[i][j][i]=k; } } cout<<f[n][m]<<endl; for(int i=1;i<=n;i++) cout<<i<<" "<<path[n][m][i]<<endl; return 0; }如果你依照上述思想写出了dp程序并提交,恭喜你,只有90分。
#那么这是为什么呢?
回到题面,我们会发现小小的一行字,人畜无害的样子:
P.S.要求答案的字典序最小你会发现如果这样做,方案输出是错的。
如何使字典序最小呢?这需要我们倒着枚举。
设表示的意思为“不给”第i家公司k台机器(k的值域同上),那么状态转移方程需改为:
f[i][j]=max(f[i][k],f[i-1][k]+graph[i][j-k]);再根据这个,对于path数组的更新操作进行一些微调,即可得到满分程序了:
#include<bits/stdc++.h> using namespace std; int f[11][16],graph[11][16],path[11][16][11],n,m; int main() { cin>>n>>m; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) cin>>graph[i][j]; } memset(f,0,sizeof(f)); for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) for(int k=0;k<=j;k++) { if (f[i][j]<f[i-1][k]+graph[i][j-k]) { f[i][j]=f[i-1][k]+graph[i][j-k]; for(int h=1;h<i;h++) path[i][j][h]=path[i-1][k][h]; path[i][j][i]=j-k;//因为改为了“不给”第i家公司k台机器,所以必须如此调整 } } cout<<f[n][m]<<endl; for(int i=1;i<=n;i++) cout<<i<<" "<<path[n][m][i]<<endl; return 0; }
- 1
信息
- ID
- 1031
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者