题目大意:一个最多两列最多100行的数字矩阵,从中选出K个不重叠的矩形,他们的数字之和最大是多少?
https://ac.nowcoder.com/acm/problem/20242
看到最多有两列,可以想到关于每一行的状态进行状态压缩DP,可能状态是:空,左边被占用,右边被占用,左右被不同矩形占用,左右被一个矩形占用。需要维护dp[R][S][N]表示到R行为止处于状态S已经使用N个矩形,最大的和是多少(如果不可能该和为-INF)。状态和个数的转移不难求得,比如dp[5][左右被不同矩形占用][用了5个矩形]可以来自dp[4][空][3], dp[4][左边被占用][4],等等。
int N,M,K;
int score[105][3];
// dp[row][state][count].
int dp[105][10][20];
#define amax(a,b) a=max(a,b)
#define INF 327670000
// state = 0 <=> nothing
// state = 1 <=> left only
// state = 2 <=> right only
// state = 3 <=> left + right
// state = 4 <=> both
int doit() {
VVI trans = {
// state = 0
{0,0,0,0,0},
// state = 1
{1,0,1,0,1},
// state = 2
{1,1,0,0,1},
// state = 3
{2,1,1,0,2},
// state = 4
{1,1,1,1,0},
};
FOR(row,0,N){
for (int state = 0; state <= 4; ++state) {
for (int cnt = 0; cnt <= K; ++cnt) {
if(row==0){
if(state==0&&cnt==0){
dp[row][state][cnt]=0;
}else{
dp[row][state][cnt]=-INF;
}
} else {
dp[row][state][cnt]=-INF;
int cost = 0;
if (state==1||state==3||state==4){
cost+=score[row-1][0];
}
if(M==2){
if (state==2||state==3||state==4){
cost+=score[row-1][1];
}
}
if (state < 2 || M == 2) {
for (int prev_state=0;prev_state<=4;++prev_state){
if(cnt>=trans[state][prev_state]){
dp[row][state][cnt]=max(dp[row][state][cnt],dp[row-1][prev_state][cnt-trans[state][prev_state]]+cost);
}
}
}
}
// print(row,state,cnt,dp[row][state][cnt]);
}
}
}
int ans = -INF;
for (int state = 0; state <= 4; ++state) {
amax(ans,dp[N][state][K]);
}
return ans;
}
int main(int argc, char* argv[]) {
read(N,M,K);
REP(i,N){
REP(j,M){
scanf("%d",&score[i][j]);
}
}
printint(doit());
return 0;
} 
京公网安备 11010502036488号