bzoj1084(dp)

来源:互联网 发布:软件规格需求说明书 编辑:程序博客网 时间:2024/04/27 21:36

分了两种情况,

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;}




0 0
原创粉丝点击