题目描述
题目链接:
https://www.acwing.com/problem/content/description/1015/
思路:
本题不是难题,但是还蛮有意思,我就简单写一下博客,总结一下,也算是对自己的提醒
(解法一): 暴力DFS搜索, 复杂度: . 就是对每一个公司,暴力枚举其所有可能的方案,然后统计最大值。 这种做法没什么可以说的。
解法一的代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=16;
int a[N][N];
int n,m;
int ans=0;
int b[N];
int jie[N];
void dfs(int value,int cur,int sum){
if(sum>m) return ;
if(cur==n){
int res=value+a[n][m-sum];
b[n]=m-sum;
if(res>ans){
ans=res;
for(int i=1;i<=n;i++){
jie[i]=b[i];
}
return ;
}
return ;
}
for(int i=0;sum+i<=m;i++){
b[cur]=i;
int now_value=value+a[cur][i];
dfs(now_value,cur+1,sum+i);
}
return ;
}
int main(void){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
}
}
dfs(0,1,0);
printf("%d\n",ans);
for(int i=1;i<=n;i++){
printf("%d %d\n",i,jie[i]);
}
return 0;
}
(解法二): DP, 背包问题求方案,时间复杂度O(nm2)
用f[i][j]表示1~i 这些公司,且总共分配了j个机器的最大价值。则,不难得到状态转移:
f[i][j]=max(f[i-1][j-k]), k=0,1,...j.
最终答案: f[n][m].
此外,本题还要求我们输出最优的方案,因此需要在dp更新的时候同时记录一下是如何更新的。
pre[i][j] 表示1~i 这些公司,总共分配了j个机器时的最优决策在第i个公司处分配了多少个机器
那么就可以递归地找到最优解了
解法二的代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=16;
const int inf=-0x3f3f3f3f;
int f[N][N];
int pre[N][N];
int a[N][N];
int n,m;
int jie[N];
int main(void){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&a[i][j]);
}
}
memset(f,-0x3f,sizeof(f));
f[0][0]=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
for(int k=0;k<=j;k++){
if(f[i-1][j-k]==inf) continue;
int res=f[i-1][j-k]+a[i][k];
if(res>f[i][j]){
f[i][j]=res;
pre[i][j]=k;
}
}
}
}
int ans=f[n][m];
printf("%d\n",ans);
int now_volumn=m;
for(int i=n;i>=1;i--){
int k=pre[i][now_volumn];
now_volumn-=k;
jie[i]=k;
}
for(int i=1;i<=n;i++){
printf("%d %d\n",i,jie[i]);
}
return 0;
}