bzoj 5359 [Lydsy1805月赛]寻宝游戏

http://www.elijahqi.win/archives/3529
有k次交换数字的机会 求从1,1->n,m能够获得的最大代价是多少

因为有很多路径代价是相同的但是选择的效果却不同 在月赛的时候我直接朴素dp+贪心 秒wa

思路非常巧妙 想hack icefox大爷没成功设dp[i][j][t][z]表示当前处在i,j 这个位置 现在一路走过来有t个位置没选 z个位置是从非路径上选来的 有z个 那么分两种情况讨论即可 1、直接向右走1步

2、向下走一步这两种情况都需要分别考虑我新走到的地方是否选择了 其他的k个即 从i.j+1->i,m

i+1,1->i+1,j-1这些位置中我可能是换过来的即 非路径上的点的权值

另外因为存在不合法状态 一开始需要给-inf

#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int N=60;
int dp[N][N][22][22],T,a[N][N],n,m,k,q[N];//(i,j)位置 t个没选 z个另选的最优值
inline bool cmp(const int &a,const int &b){return a>b;}
int main(){
    freopen("bzoj5359.in","r",stdin);
    T=read();
    while(T--){
        n=read();m=read();k=read();memset(dp,128,sizeof(dp));
        for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) a[i][j]=read();
        dp[1][1][0][0]=a[1][1];dp[1][1][1][0]=0;
        for (int i=1;i<=n;++i){
            for (int j=1;j<=m;++j){
                if (i!=n) {int nn=0;
                    for (int ii=j+1;ii<=m;++ii) q[++nn]=a[i][ii];
                    for (int ii=1;ii<j;++ii) q[++nn]=a[i+1][ii];sort(q+1,q+nn+1,cmp);
                    for (int ii=1;ii<=nn;++ii) q[ii]=q[ii-1]+q[ii];
                    for (int t=0;t<=k;++t){
                        for (int z=0;z<=k;++z){
                            for (int x=0;x<=nn&&x+z<=k;++x){
                                if (t<k) dp[i+1][j][t+1][z+x]=max(dp[i+1][j][t+1][z+x],dp[i][j][t][z]+q[x]);
                                dp[i+1][j][t][z+x]=max(dp[i+1][j][t][z+x],dp[i][j][t][z]+q[x]+a[i+1][j]);
                            }
                        }
                    }
                }
                if (j==m) continue;
                for (int t=0;t<=k;++t){
                    for (int z=0;z<=k;++z){
                        dp[i][j+1][t][z]=max(dp[i][j+1][t][z],dp[i][j][t][z]+a[i][j+1]);
                        if (t<k) dp[i][j+1][t+1][z]=max(dp[i][j+1][t+1][z],dp[i][j][t][z]);
                    }
                }
            }
        }int ans=0;
        for (int i=0;i<=k;++i) ans=max(ans,dp[n][m][i][i]);printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/elijahqi/article/details/80489353
今日推荐