题意:给定一个M*N矩阵,需要按照横纵轴cut得到M*N个1*1的submatric,每次cut一次得到的coin是矩阵中最小数的值。求最优解是的得到的coin数最大。
small input是一个vector,可以枚举分割的行数。large input想法类似,只不过改成dp,dp[a,b,c,d]表示左上角[a,b]右下角[c,d]的submatrix最优解的情况下得到的coin是多少。状态转移时分别枚举按某一行cut或者按某一列cut:
dp[a,b,c,d]=max(dp[a,b,i,d]+dp[i+1,b,c,d]+min_value[a,b,c,d], dp[a,b,c,j]+dp[a,j+1,c,d]+min_value[a,b,c,d])for all a<=i<c,b<=j<d
min_value[a,b,c,d]表示submatrix中的最小值,可以先O(N^4)预处理。转移时只要和新加入的一列的最小值比较即可。min_value[a,b,c,d]=min(min_value[a,b,c,d-1],min of mp[a~c,d])
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<windows.h>
using namespace std;
//Kcikstart 2017 Round D Problem B. Cards Game
const int maxn=42;
int T;
int N;
int M;
int mp[maxn][maxn];
int dp[maxn][maxn][maxn][maxn];
int min_value[maxn][maxn][maxn][maxn];
int ans;
int dfs(int a,int b,int c,int d)
{
if(a==c&&b==d)
{
return 0;
}
if(dp[a][b][c][d]!=0)//each value is >0
{
return dp[a][b][c][d];
}
int horizon_min=0;
int vertical_min=0;
for(int i=a;i<c;i++)//horizontal line
{
int val=dfs(a,b,i,d)+dfs(i+1,b,c,d)+min_value[a][b][c][d];
horizon_min=max(horizon_min,val);
}
for(int i=b;i<d;i++)//vertical line
{
int val=dfs(a,b,c,i)+dfs(a,i+1,c,d)+min_value[a][b][c][d];
vertical_min=max(vertical_min,val);
}
dp[a][b][c][d]=max(vertical_min,horizon_min);
// cout<<a<<" "<<b<<" "<<c<<" "<<d<<" "<<dp[a][b][c][d]<<endl;
return dp[a][b][c][d];
}
int main()
{
// freopen("input.txt","r",stdin);
freopen("C-large-practice.in","r",stdin);
freopen("C.txt","w",stdout);
cin>>T;
for(int ca=1;ca<=T;ca++)
{
memset(mp,0,sizeof(mp));
memset(dp,0,sizeof(dp));
memset(min_value,0,sizeof(min_value));
ans=0;
scanf("%d %d",&N,&M);
for(int i=0;i<N;i++)
{
for(int j=0;j<M;j++)
{
scanf("%d",&mp[i][j]);
}
}
//pre process min value
for(int i=0;i<N;i++)
{
for(int j=0;j<M;j++)
{
min_value[i][j][i][j]=mp[i][j];
dp[i][j][i][j]=mp[i][j];
}
}
for(int i=0;i<N;i++)
{
for(int j=0;j<M;j++)
{
for(int k=i+1;k<N;k++)
{
min_value[i][j][k][j]=min(min_value[i][j][k-1][j],mp[k][j]);
}
for(int k=j+1;k<M;k++)
{
min_value[i][j][i][k]=min(min_value[i][j][i][k-1],mp[i][k]);
}
for(int l=i+1;l<N;l++)
{
for(int m=j+1;m<M;m++)
{
int mini=0x3f3f3f3f3f;
for(int k=i;k<=l;k++)
{
mini=min(mini,mp[k][m]);
}
min_value[i][j][l][m]=min(min_value[i][j][l][m-1],mini);
// cout<<i<<" "<<j<<" "<<l<<" "<<m<<" "<<min_value[i][j][l][m]<<endl;
}
}
}
}
// for(int i=0;i<N;i++)
// {
// for(int j=0;j<M;j++)
// {
// for(int l=i;l<N;l++)
// {
// for(int m=j;m<M;m++)
// {
// cout<<i<<" "<<j<<" "<<l<<" "<<m<<" "<<min_value[i][j][l][m]<<endl;
// }
// }
// }
// }
ans=dfs(0,0,N-1,M-1);
// for(int i=0;i<N;i++)
// {
// for(int j=0;j<N;j++)
// {
// cout<<mp[i][j]<<" ";
// }
// cout<<endl;
// }
printf("Case #%d: %d\n",ca,ans);
cerr<<"finish case "<<ca<<endl;
}
return 0;
}
附上dfs for small input
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
//kickstart 2017 Round G Problem A
int T;
const int maxn=20;
int N;
int M;
int ans;
int mat[maxn][maxn];
int dfs(int st,int ed)//[st,...,ed]
{
//cout<<st<<" "<<ed<<endl;
if(st==ed)
{
return 0;
}
// find min
int mini=0x3f3f3f3f;
for(int i=st;i<=ed;i++)
{
mini=min(mini,mat[0][i]);
//cout<<mat[0][i]<<endl;
}
int maxret=0;
for(int i=st;i<ed;i++)
{
maxret=max(maxret,dfs(st,i)+dfs(i+1,ed));
}
return maxret+mini;
}
int main()
{
freopen("C-small-attempt0.in","r",stdin);
//freopen("input.txt","r",stdin);
freopen("c1.txt","w",stdout);
scanf("%d",&T);
for(int ca=1;ca<=T;ca++)
{
ans=0;
scanf("%d %d",&N,&M);
for(int i=0;i<N;i++)
{
for(int j=0;j<M;j++)
{
scanf("%d",&mat[i][j]);
}
}
ans=dfs(0,M-1);
printf("Case #%d: %d\n",ca,ans);
}
return 0;
}