1:解前的内心挣扎ops
看一眼数据这么小,enm........,那就搜索水过吧~(狗头)
等等正解还是dp!,我们这是平时练习,要练!dp呢还是搜索呢,啊啊啊啊啊,dp吧~,dp好难,不!~,硬着头皮上,最后up决定两种都写!~(狗头)
2:
dp思路:
一道经典的区间DP练习题。
设f[i][j]为前i个公司总共分配j台机器的最大利润。对于第i家子公司,我们可以给其分配的机器台数为:0,1,2……m
所以在该区间内枚举一个值k,状态转移方程即为:
f[i][j]=max(f[i-1][j-k],f[i][j]);
那么,如何处理方案输出问题呢?
我们设p[i][j][h]
对于前i个公司共分配j台机器的最优方案,第h个公司应分配多少台机器,当状态发生转移时,更新path数组即可。最终的答案就存放在p[n][m][i]
之中。
注意这里转移的时候是小于等于(有等于这样子就可以做到按字典序从小到大排列)
ACcode:
#include<bits/stdc++.h>
using namespace std;
const int N=20;
int f[N][N],w[N][N],p[N][N][N],n,m;
void solve(){
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>w[i][j];
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]+w[i][k]){
f[i][j]=f[i-1][j-k]+w[i][k];
for(int h=1;h<i;h++) p[i][j][h]=p[i-1][j-k][h];
p[i][j][i]=k;
}
}
cout<<f[n][m]<<"\n";
for(int i=1;i<=n;i++){
cout<<i<<" "<<p[n][m][i]<<"\n";
}
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
solve();
return 0;
}
3:dfs就是枚举每种方法(没啥好说,很经典~)
ACcode:(代码思路挺清晰的)
#include<bits/stdc++.h>
using namespace std;
const int N=20;
int n,m,a[N],b[N],w[N][N],mmax=-1;
void dfs(int pos,int sum,int k){
if(k>m) return;
if(pos>n){
if(sum>mmax){
mmax=sum;
for(int j=1;j<=n;j++) b[j]=a[j];
}
return;
}
for(int i=0;i<=m;i++){
a[pos]=i;
dfs(pos+1,sum+w[pos][i],k+i);
}
}
void solve(){
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>w[i][j];
dfs(1,0,0);
cout<<mmax<<"\n";
for(int i=1;i<=n;i++) cout<<i<<" "<<b[i]<<"\n";
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
solve();
return 0;
}
over~