A Refining Company LightOJ - 1036
描述好长啊...
题意:在m*n的矩阵上,每一格摆一个向上或者向左的传送带(不能同时摆,只能摆一个)。同时,每一格有两种物资Uranium和Radium。会给出两个矩阵,分别表明每一格Uranium和Radium的数量。每一种物资可以通过传送带按照其方向传送,但不能转向(遇到不同方向的传送带物品就失效)。Radium要送到上面(第一行任意位置),Uranium要送到左面(左起第一列任意位置),送到错误位置的物资将废弃。求最终送到正确位置的物资数量总和的最大值。
方法:容易发现,最大结果所对应的传送带方向中,一定不会有某个向左的传送带在任何向上的传送带的右侧或上侧,不然将其变为向上的传送带结果一定不会变差;一定不会有某个向上的传送带在任何向左的传送带的左侧或下侧,不然将其变为向左的传送带结果一定不会变差。
因此,状态ans[i][j]表示第i行前j列向左时最大得分。
sumu[i][j]表示第i行前j列以外的格子的向上得分之和
suml[i][j]表示第i行前j列的向左得分之和
那么,$ans[i][j]=max{ans[i-1][p]}(0<=p<=j)+suml[i][j]+sumu[i][j]$。预处理sumu和suml是不难的。计算ans时,随便在算同一行的时候用奇怪的方法(应该叫...前缀max?)记录一下max就是$O(mn)$。答案就是最后一行ans的最大值。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 int T,TT,m,n,t_max; 5 int l[510][510],u[510][510],suml[510][510],sumu[510][510],ans[510][510]; 6 int main() 7 { 8 int i,j; 9 scanf("%d",&T); 10 for(TT=1;TT<=T;TT++) 11 { 12 scanf("%d%d",&m,&n); 13 for(i=1;i<=m;i++) 14 for(j=1;j<=n;j++) 15 scanf("%d",&l[i][j]); 16 for(i=1;i<=m;i++) 17 for(j=1;j<=n;j++) 18 scanf("%d",&u[i][j]); 19 for(i=1;i<=m;i++) 20 { 21 for(j=1;j<=n;j++) 22 suml[i][j]=suml[i][j-1]+l[i][j]; 23 sumu[i][n]=0; 24 for(j=n-1;j>=0;j--) 25 sumu[i][j]=sumu[i][j+1]+u[i][j+1]; 26 } 27 for(j=0;j<=n;j++) 28 ans[1][j]=suml[1][j]+sumu[1][j]; 29 for(i=2;i<=m;i++) 30 { 31 t_max=0; 32 for(j=0;j<=n;j++) 33 { 34 t_max=max(t_max,ans[i-1][j]); 35 ans[i][j]=t_max+suml[i][j]+sumu[i][j]; 36 } 37 } 38 t_max=0; 39 for(j=0;j<=n;j++) 40 t_max=max(t_max,ans[m][j]); 41 printf("Case %d: %d ",TT,t_max); 42 } 43 return 0; 44 }