LightOJ1036 A Refining Company(DP)

时间:2022-02-09 16:06:23

题目大概说有一个n*m的格子地图,每个格子有铀或者镭矿。地图最北面的镭矿加工厂,最西面有铀矿加工厂,而要通过在格子里铺设由南向北(镭)或由东向西(铀)的轨道来送矿物到加工厂。一个格子只能铺设一种轨道,即要嘛运送铀要嘛运送镭,不同轨道也不能相交。现在知道地图上各个格子铀和镭的数量,问怎么铺设轨道使送到加工厂的矿物数量最多。

  • 首先明确要运送某一格子的镭矿到北面加工厂,这个轨道肯定是直直连续往上的;而铀矿同理,是水平连续向左的轨道。
  • 另外,因为获得的数量要最多,各个格子肯定都要铺设轨道,反证可知。
  • 然后可以发现,格子(i,j)怎样与格子(0,0)到格子(i-1,j-1)的围成的矩形所有格子的情况毫不相关,这样就考虑DP了:
    1. dp[0][i][j]表示格子(0,0)到格子(i,j)围成的矩形中,格子(i,j)铺设横轨道能获得的最大数量
    2. dp[1][i][j]表示格子(0,0)到格子(i,j)围成的矩形中,格子(i,j)铺设竖轨道能获得的最大数量

转移:

    1. dp[0][i][j]就是从max(dp[0][i-1][j],dp[1][i-1][j])+sum(格子(i,0)的铀数量...格子(i,j)的铀数量)
    2. dp[1][i][j]同理
  • 而最后的结果就是max(dp[0][n-1][m-1],dp[1][n-1][m-1])
 #include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; int U[][],R[][],d[][][];
int main(){
int t,n,m;
scanf("%d",&t);
for(int cse=; cse<=t; ++cse){
scanf("%d%d",&n,&m);
for(int i=; i<n; ++i){
for(int j=; j<m; ++j){
scanf("%d",&U[i][j]);
}
}
for(int i=; i<n; ++i){
for(int j=; j<m; ++j){
scanf("%d",&R[i][j]);
}
}
memset(d,,sizeof(d));
d[][][]=U[][];
d[][][]=R[][];
for(int i=; i<n; ++i){
for(int j=; j<m; ++j){
if(i== && j==) continue;
if(i==){
int sum=;
for(int k=; k<=j; ++k){
sum+=U[i][k];
}
d[][i][j]=sum; d[][i][j]=max(d[][i][j-],d[][i][j-])+R[i][j];
}else if(j==){
d[][i][]=max(d[][i-][],d[][i-][])+U[i][j]; int sum=;
for(int k=; k<=i; ++k){
sum+=R[k][j];
}
d[][i][j]=sum;
}else{
int sum=;
for(int k=; k<=j; ++k){
sum+=U[i][k];
}
d[][i][j]=max(d[][i-][j],d[][i-][j])+sum; sum=;
for(int k=; k<=i; ++k){
sum+=R[k][j];
}
d[][i][j]=max(d[][i][j-],d[][i][j-])+sum;
}
}
}
printf("Case %d: %d\n",cse,max(d[][n-][m-],d[][n-][m-]));
}
return ;
}