A Refining Company LightOJ - 1036

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\n",TT,t_max);
42     }
43     return 0;
44 }
posted @ 2017-10-27 21:38  hehe_54321  阅读(173)  评论(0编辑  收藏  举报
AmazingCounters.com