1. 程式人生 > >5359: [Lydsy1805月賽]尋寶遊戲 DP

5359: [Lydsy1805月賽]尋寶遊戲 DP

題解:

選擇 k k 個位置交換實際上是一條路徑上,有 k k 個屬於這條路徑上的權值不計貢獻,有 k

k 個不屬於路徑的權值計入貢獻。所以直接DP, f [ i ] [ j ] [
p ] [ q ] f[i][j][p][q]
表示到了 ( i
, j ) (i,j)
,路徑上有 p p 個權值不計貢獻,在前 i 1 i-1 行和第 i i 行的前 j j 個沒選的權值中有 q q 個權值計入貢獻即可。

程式碼:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=55;
const int Maxk=25;
const int inf=2147483647;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x*f;
}
int n,m,k,a[Maxn][Maxn],f[Maxn][Maxn][Maxk][Maxk];
int d[Maxn],s[Maxn];
void upd(int &x,int y){x=max(x,y);}
bool cmp(int x,int y){return x>y;}
int main()
{
    int T=read();
    while(T--)
    {
        memset(f,-1,sizeof(f));
        n=read(),m=read(),k=read();
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        a[i][j]=read();
        f[1][1][0][0]=a[1][1];
        f[1][1][1][0]=0;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            int c=0;
            for(int l=j+1;l<=m;l++)d[++c]=a[i][l];
            for(int l=1;l<j;l++)d[++c]=a[i+1][l];
            sort(d+1,d+1+c,cmp);
            s[0]=0;
            for(int l=1;l<=c;l++)s[l]=s[l-1]+d[l];
            for(int p=0;p<=k;p++)
            for(int q=0;q<=k;q++)
            if(f[i][j][p][q]!=-1)
            {
                int t=f[i][j][p][q];
                if(j<m)
                {
                    upd(f[i][j+1][p][q],t+a[i][j+1]);
                    if(p<k)upd(f[i][j+1][p+1][q],t);
                }
                if(i<n)
                {
                    upd(f[i+1][j][p][q],t+a[i+1][j]);
                    if(p<k)upd(f[i+1][j][p+1][q],t);
                    for(int l=1;q+l<=k&&l<=c;l++)
                    {
                        upd(f[i+1][j][p][q+l],t+a[i+1][j]+s[l]);
                        if(p<k)upd(f[i+1][j][p+1][q+l],t+s[l]);
                    }
                }
            }
        }
        int ans=0;
        for(int i=0;i<=k;i++)upd(ans,f[n][m][i][i]);
        printf("%d\n",ans);
    }
}