zzzyc
2018-01-07 19:27:05
看到很多大佬写的都是些高端的dp。。。
小蒟蒻表示看不懂啊。。。
所以想了个简单的方法。。。
#include<iostream>
using namespace std;
int n,m,k,a[201][201];
int sy[201][201],sn[201][201];
int fn[201][201],fy[201][201];
bool b[201][201];
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
char ch;
cin>>a[i][j]>>ch;
if(ch=='Y') b[i][j]=1;
}
for(int i=1;i<=m;i++)
{
int cnt=0;
for(int j=n;j>=1;j--)
{
if(b[j][i]==1)
sy[i][cnt]+=a[j][i];
else
{
cnt++;
sy[i][cnt]=sy[i][cnt-1]+a[j][i];
sn[i][cnt]=sy[i][cnt-1]+a[j][i];
}
}
}
for(int x=1;x<=m;x++) 第x列
for(int y=0;y<=k;y++) 总共y颗子弹
for(int z=0;z<=n && z<=y;z++) 要用z颗
{
fy[x][y]=max(fy[x][y],fy[x-1][y-z]+sy[x][z]);
if(z!=0) fn[x][y]=max(fn[x][y],fy[x-1][y-z]+sn[x][z]); 后打x列
if(y-z>0) fn[x][y]=max(fn[x][y],fn[x-1][y-z]+sy[x][z]); 先打x列
// 解释的好像有点问题。。。但大意就参照下文吧。。。
}
cout<<fn[m][k];
}
// 有借子弹的情况,预处理:sy[i][j],sn[i][j]表示第i列用j个子弹的得分
// y表示最后一颗不是在i列打的,n表示是
// fn[i][j],fy[i][j]表示前i列一共消耗j颗子弹,最后一颗是否打在第i列上
// 这个题很神奇。。。用到的方法就是先算出每列用的子弹数。。。会得多少分
// 然后dp的时候处理一下每种情况下最后一颗子弹就可以了
// 因为最后不一定要一棵树上吊死,可是子弹不够怎么办。。。
// 假装有。。。到底有没有就不知道了。。。如果没有预处理的没有用。。。
// 不会对后来的情况造成影响。。。
而且跑的蛮快的。。。