洛谷 P1174 打砖块

虽然打到标记为Y的砖块上相当于没有消耗子弹,但是首先需要从别的列“借”一发子弹。因为如果没有子弹打在上面,我们无法获得奖励的子弹和分数。

所谓借一发子弹,其实是打子弹的先后顺序,比如第2列要借一发子弹给第1列,那么把将要打第2列的一发子弹先用来打第1列,然后第1列获得奖励的子弹后,再把那一发子弹还给第二列。

dp[i][j][0]表示前i列用了j发子弹且最后一发打在标记为N的砖块上的最大分数,dp[i][j][1]表示前i列用了j发子弹且最后一发打在标记为Y的砖块上的最大分数。

首先预处理把所有标记为Y的砖块压到它下面标记为N的砖块上,用s[i][j][0]表示第i列用了j发子弹且最后一发打在标记为N的砖块上获得的分数,s[i][j][1]表示第i列用了j发子弹且最后一发打在标记为Y的砖块上获得的分数。

最后的答案一定是打在标记为N的砖块上,即dp[m][K][0],如果打在Y的砖块上,还可以继续再打,一定不是最优的。

#include<bits/stdc++.h>
using namespace std;
int n,m,K;
int w[210][210],dp[210][210][2];
int s[210][210][2];
bool op[210][210];
char ch;
int main()
{
    cin>>n>>m>>K;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>w[i][j]>>ch;
            if(ch=='Y') op[i][j]=1;
        }
    }
    for(int j=1;j<=m;j++){
        int cnt=0;
        for(int i=n;i>=1;i--){
            if(op[i][j])
            s[j][cnt][1]+=w[i][j];
            else{
                ++cnt;
                s[j][cnt][0]=s[j][cnt][1]=s[j][cnt-1][1]+w[i][j];
            }
        }
    }
    for(int i=1;i<=m;i++){
        for(int j=0;j<=K;j++){
            for(int k=0;k<=n&&k<=j;k++){
                dp[i][j][1]=max(dp[i][j][1],dp[i-1][j-k][1]+s[i][k][1]);
                 //dp[i-1][j-k][1]一定会剩下一枚子弹,用于打第i列的第k个标记为Y的砖块,打完后同样会剩下一枚子弹
                if(k) dp[i][j][0]=max(dp[i][j][0],dp[i-1][j-k][1]+s[i][k][0]);
                 //第i列借一发子弹给前i-1列,最终打在第i列上
                if(j>k) dp[i][j][0]=max(dp[i][j][0],dp[i-1][j-k][0]+s[i][k][1]);
                 //前i-1列借一发子弹给第i列,最终打在前i-1列上
            }
        }
    }
    cout<<dp[m][K][0]<<endl;
    return 0;
}

 

posted @ 2020-04-14 19:48  --HY--  阅读(271)  评论(0编辑  收藏  举报