分了两种情况,
m==1时,dp即可,关键是要注意负数的处理,有负数的时候,初始化为0就很可能有bug
m==2时,想了一个dp,然而有一种情况没有考虑,codevs数据真是良心,给我留了90分,先贴自己的代码,然后重新写一下
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f;
int f[109][109][3][5],a[109][3],n,m,k,dp[109][12];
int work1()
{
int f[109][120][2],a[109];
memset(f,-inf,sizeof(f));
memset(a,0,sizeof(a));
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
f[1][1][1]=a[1];f[1][0][0]=0;
for (int i=2;i<=n;i++)
{
f[i][0][0]=0;
for (int j=1;j<=min(k,i);j++)
{
f[i][j][1]=max(f[i-1][j][1]+a[i],max(f[i-1][j-1][0]+a[i],f[i-1][j-1][1]+a[i]));
f[i][j][0]=max(f[i-1][j][1],f[i-1][j][0]);
}
}
return max(f[n][k][1],f[n][k][0]);//当m==1时,情况处理
}
int max(int a,int b,int c,int d)
{
return max(max(a,b),max(c,d));
}
int work2()//m==2时
{
for (int i=1;i<=n;i++) scanf("%d%d",&a[i][1],&a[i][2]),a[i][0]=a[i][1]+a[i][2];
memset(f,-inf,sizeof(f));
for (int kk=0;kk<3;kk++)
{
for (int i=n;i>=1;i--)
{
f[i][i][kk][3]=f[i][i][kk][4]=a[i][kk];
f[i][i][kk][0]=f[i][i][kk][1]=f[i][i][kk][2]=0;
for (int j=i+1;j<=n;j++)
{
f[i][j][kk][0]=
max(f[i][j-1][kk][0],f[i][j-1][kk][1],f[i+1][j][kk][2],f[i+1][j][kk][0]);
f[i][j][kk][1]=a[j][kk]+f[i][j-1][kk][1];
f[i][j][kk][2]=a[i][kk]+f[i+1][j][kk][2];
f[i][j][kk][3]=
max(f[i][j-1][kk][3]+a[j][kk],f[i+1][j][kk][3]+a[i][kk]);
f[i][j][kk][4]=max(f[i][j][kk][1],f[i][j][kk][2],f[i][j][kk][3],f[i][j][kk][0]);
}
}
}//处理区间i~j,的最大值
/*for (int i=1;i<=n;i++)
for (int j=i;j<=n;j++)
printf("%d %d %d\n",i,j,f[i][j][2][4]);*/
memset(dp,-inf,sizeof(dp));
dp[0][0]=0;
for (int i=1;i<=n;i++)
{
dp[i][0]=0;
for (int j=1;j<=min(i,k);j++)
{
for (int l=1;l<=i;l++)
{
dp[i][j]=
max(dp[i][j],dp[l-1][j-1]+f[l][i][0][4],dp[l-1][j-1]+f[l][i][1][4],dp[l-1][j-1]+f[l][i][2][4]);
if (j>1) dp[i][j]=max(dp[i][j],dp[l-1][j-2]+f[l][i][1][4]+f[l][i][2][4]);
}
}
}
return dp[n][k];
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
if (m==1) printf("%d",work1());
else printf("%d",work2());
return 0;
}
标准做法
f[i][j][k]表示第一列前i个数字,第二列前j个数字选出k个子矩阵的最大分值
转移还是O(N)
f[i][j][k] = max(f[i - 1][j][k], f[i][j - 1][k]);//不选这个点
如果选
f[i][j][k] = max{ f[i][j][k], f[x][j][k - 1] + s1[i] - s1[x] };//从左列枚举点,更新
f[i][j][k] = max{ f[i][j][k], f[i][y][k - 1] + s2[j] - s2[y] };//从右列枚举,更新
当 i = j 时 f[i][j][k] = max{ f[i][j][k], f[x][x][k - 1] + s1[i] - s1[x] + s2[i] - s2[x] };//如果他们是相平的,就可以枚举两行的情况两了
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f;
int f[109][109][12],a[109][3],n,m,k,dp[109][12],sum[109][3];
int work1()
{
int f[109][120][2],a[109];
memset(f,-inf,sizeof(f));
memset(a,0,sizeof(a));
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
f[1][1][1]=a[1];f[1][0][0]=0;
for (int i=2;i<=n;i++)
{
f[i][0][0]=0;
for (int j=1;j<=min(k,i);j++)
{
f[i][j][1]=max(f[i-1][j][1]+a[i],max(f[i-1][j-1][0]+a[i],f[i-1][j-1][1]+a[i]));
f[i][j][0]=max(f[i-1][j][1],f[i-1][j][0]);
}
}
return max(f[n][k][1],f[n][k][0]);//当m==1时,情况处理
}
int work2()//m==2时
{
for (int i=1;i<=n;i++) scanf("%d%d",&a[i][1],&a[i][2]);
for (int i=1;i<=n;i++) sum[i][1]=sum[i-1][1]+a[i][1],sum[i][2]=sum[i-1][2]+a[i][2];
for (int l=1;l<=k;l++)
for (int a1=0;a1<=n;a1++)
for (int a2=0;a2<=n;a2++)
{
if (a1+a2<l) continue;
if (a1+a2==l)
{
f[a1][a2][l]=sum[a1][1]+sum[a2][2];
continue;
}
if (a1)
{
f[a1][a2][l]=f[a1-1][a2][l];
for (int j=0;j<a1;j++)
f[a1][a2][l]=max(f[a1][a2][l],f[j][a2][l-1]+sum[a1][1]-sum[j][1]);
}
if (a2)
{
f[a1][a2][l]=max(f[a1][a2-1][l],f[a1][a2][l]);
for (int j=0;j<a2;j++)
f[a1][a2][l]=max(f[a1][a2][l],f[a1][j][l-1]+sum[a2][2]-sum[j][2]);
}
if (a1==a2)
{
for (int j=0;j<a1;j++)
f[a1][a2][l]=
max(f[a1][a2][l],f[j][j][l-1]+sum[a1][1]-sum[j][1]+sum[a2][2]-sum[j][2]);
}
}
return f[n][n][k];
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
if (m==1) printf("%d",work1());
else printf("%d",work2());
return 0;
}