题目传送门
https://codeforces.com/problemset/problem/946/D
题目分析
这肯定是一个动态规划问题,由于统计代价是以行为单位的,我们可以将前 行作为我们的阶段。同时两个阶段之间的转移依靠对本行1的消除,这类似于01背包问题。容易想到,我们要分别计算花费不同的情况下能够减少的代价,同时对于一个花费,只需记录减少代价的最大值即可。这样我们就对每个阶段得到了不同花费与收益的‘商品’,然后使用01背包与依赖性背包问题解决即可,参考题解P3961 [TJOI2013] 黄金矿工
代码
#include <iostream>
#include <cstring>
using namespace std;
int n,m,K,tot=0;
int maps[501][501],shot[501][501],cnt[501];//shot[i][j]表示第i行第j个1的位置,cnt[i]表示第i行1的数量
int f[501][501],cost[501],g[501];//cost[i]代表第i行的花费,g[i]代表某行内花费i个成本将缩减多少个花费,f[i][j]表示前i行,花费j所减去的最大收益
int r[501][501];//r[i][j]表示第i行花费为j的收益
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> K;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char c;
cin >> c;
maps[i][j]=c-'0';
}
}
for(int i=1;i<=n;i++){
int first=n+1,last=0;
for(int j=1;j<=m;j++){
if(!maps[i][j])
continue;
first=min(first,j);
last=max(last,j);
cnt[i]++;
shot[i][cnt[i]]=j;
}
if(first==n+1&&last==0)
cost[i]=0;
else
cost[i]=last-first+1;
tot+=cost[i];
}
for(int i=1;i<=n;i++){
memset(g,0,sizeof(g));
for(int j=1;j<=cnt[i];j++){
for(int k=j;k<=cnt[i];k++){
int dec=cnt[i]-k+j-1;
g[dec]=max(g[dec],cost[i]-(shot[i][k]-shot[i][j]+1));
}
}
g[cnt[i]]=cost[i];
for(int j=0;j<=cnt[i];j++)
r[i][j]=g[j];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=K;j++){
for(int k=0;k<=cnt[i];k++){//准备在第i行花费多少进行消除
if(k>j)
break;
f[i][j]=max(f[i][j],f[i-1][j-k]+r[i][k]);
}
}
}
cout << tot-f[n][K];
return 0;
}
190

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



