Sgu167 I-country
题目描述
在 N*M 的矩阵中,每个格子有一个权值,要求寻找一个包含 K 个格子的凸连通块(连通块中间没有空缺,并且轮廓是凸的,如右图所示),使这个连通块中的格子的权值和最大。求出这个最大的权值和.N,M≤15,K≤225。
输入格式
第一行给出N,M,K,接下来给出这个矩阵
输出格式
如题
首先我们要明确凸连通块是什么:
它是一个连通块。从上往下看,它的左端点下标先递减后递增,右端点下标先递增后递减。
根据这一点,我们能够设计出这样的状态:
设dp(i,j,l,r,0/1,0/1)表示当前为第i行,已经用了j个格子,凸连通块在第i行的左端点为l,右端点为r,左端点现在在递增(0)还是递减(1),右端点在递增(0)还是递减(1)。那么可以列出状态转移方程:
\[len=r-l+1\\
dp[i][j][l][r][1][0]=\sum_{p=l}^{r}a[i][p]+Max_{l≤p≤q≤r}{\{}dp[i-1][j-len][p][q][1][0]{\}}\\
dp[i][j][l][r][1][1]=\sum_{p=l}^{r}a[i][p]+Max_{l≤p≤r≤q}{\{}Max_{0≤y≤1}{\{}dp[i-1][j-len][p][q][1][y]{\}}{\}}\\
dp[i][j][l][r][0][0]=\sum_{p=l}^{r}a[i][p]+Max_{p≤l≤q≤r}{\{}Max_{0≤x≤1}{\{}dp[i-1][j-len][p][q][x][0]{\}}{\}}\\
dp[i][j][l][r][0][1]=\sum_{p=l}^{r}a[i][p]+Max_{p≤l≤r≤q}{\{}Max_{0≤x≤1}{\{}Max_{0≤y≤1}{\{}dp[i-1][j-len][p][q][x][y]{\}}{\}}{\}}
\]
初始化都为0,目标状态:Max{dp(i,K,l,r,x,y)}。
时间复杂度为O(N * M^4 * K)
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 16
#define maxm 226
using namespace std;
int dp[maxn][maxm][maxn][maxn][2][2];
int n,m,sum,val[maxn][maxn];
int ans;
inline int read(){
register int x(0),f(1); register char c(getchar());
while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int main(){
n=read(),m=read(),sum=read();
for(register int i=1;i<=n;i++){
for(register int j=1;j<=m;j++) val[i][j]=val[i][j-1]+read();
}
for(register int i=1;i<=n;i++){
for(register int j=1;j<=sum;j++){
for(register int l=1;l<=m;l++){
for(register int r=l;r<=m;r++){
if(j<r-l+1) break;
for(register int p=l;p<=r;p++){
for(register int q=p;q<=r;q++){
dp[i][j][l][r][1][0]=max(dp[i][j][l][r][1][0],dp[i-1][j-(r-l+1)][p][q][1][0]+val[i][r]-val[i][l-1]);
}
}
for(register int p=l;p<=r;p++){
for(register int q=r;q<=m;q++){
dp[i][j][l][r][1][1]=max(dp[i][j][l][r][1][1],max(dp[i-1][j-(r-l+1)][p][q][1][0],dp[i-1][j-(r-l+1)][p][q][1][1])+val[i][r]-val[i][l-1]);
}
}
for(register int p=1;p<=l;p++){
for(register int q=l;q<=r;q++){
dp[i][j][l][r][0][0]=max(dp[i][j][l][r][0][0],max(dp[i-1][j-(r-l+1)][p][q][0][0],dp[i-1][j-(r-l+1)][p][q][1][0])+val[i][r]-val[i][l-1]);
}
}
for(register int p=1;p<=l;p++){
for(register int q=r;q<=m;q++){
dp[i][j][l][r][0][1]=max(dp[i][j][l][r][0][1],max(dp[i-1][j-(r-l+1)][p][q][0][1],max(dp[i-1][j-(r-l+1)][p][q][1][0],max(dp[i-1][j-(r-l+1)][p][q][1][1],dp[i-1][j-(r-l+1)][p][q][0][0])))+val[i][r]-val[i][l-1]);
}
}
if(j==sum) ans=max(ans,max(dp[i][j][l][r][0][0],max(dp[i][j][l][r][1][0],max(dp[i][j][l][r][0][1],dp[i][j][l][r][1][1]))));
}
}
}
}
printf("%d\n",ans);
return 0;
}