POJ 2948 Martian Mining
题意:如下图,有一种n*m的网格,每个格子里可能分别有两种矿物a[i][j]和b[i][j],在网格的上边和左边分别有这两种矿物的收集站。对每个网格,可以建立向上或者向左的传送带,将该格所有矿物传送。但是,传送带不能变方向,否则变方向之前的矿物会从传送带上掉落下来。比如,矿物如果从(i,j)传送到(i,j-1),再传送到(i-1,j-1),就会掉落。问最终能收集到的矿物最多为多少(两种矿物数量之和)。
解法:首先,对于第(i,j)格,如果它向左传送,则应该让(i,0), (i,1)...(i,j-1)都向左传送。向上同理。
设d[i][j][0]表示第(i, j)格向左传送的情况下,矩形(0,0)-(i,j)所能收集到最多的矿石数,d[i][j][1]表示第(i, j)格向上传送的情况下,矩形(0,0)-(i,j)所能收集到最多的矿石数。设wes[i][j]表示收集点在左边的矿石(i,0),(i,1)...(i,j)格共有多少,nor[i][j]表示收集点在上边的矿石(0,j),(1,j),(2,j)...(i,j)格共有多少。
wes和nor数组递推易求,d数组的状态转移方程为:d[i][j][0] = wes[i][j] + max(d[i-1][j][0], d[i-1][j][1]),d[i][j][1] = nor[i][j] + max(d[i][j-1][0], d[i][j-1][1])。
tag:网格类dp
1 /* 2 * Author: Plumrain 3 * Created Time: 2013-11-18 17:03 4 * File Name: DP-POJ-2948.cpp 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 10 using namespace std; 11 12 #define CLR(x) memset(x, 0, sizeof(x)) 13 14 int n, m; 15 int d[505][505][2]; 16 int x[505][505][2]; 17 int nor[505][505], wes[505][505]; 18 19 void init() 20 { 21 for (int t = 0; t < 2; ++ t) 22 for (int i = 0; i < n; ++ i) 23 for (int j = 0; j < m; ++ j) 24 scanf ("%d", &x[i][j][t]); 25 26 CLR (nor); CLR (wes); 27 for (int i = 0; i < n; ++ i) 28 for (int j = 0; j < m; ++ j){ 29 wes[i][j] = (j ? x[i][j][0]+wes[i][j-1] : x[i][j][0]); 30 nor[i][j] = (i ? x[i][j][1]+nor[i-1][j] : x[i][j][1]); 31 } 32 } 33 34 int DP() 35 { 36 CLR (d); 37 d[0][0][0] = x[0][0][0]; d[0][0][1] = x[0][0][1]; 38 for (int i = 0; i < n; ++ i) 39 for (int j = 0; j < m; ++ j){ 40 if (!i && !j) continue; 41 d[i][j][0] = wes[i][j]; 42 if (i) 43 d[i][j][0] += max(d[i-1][j][0], d[i-1][j][1]); 44 d[i][j][1] = nor[i][j]; 45 if (j) 46 d[i][j][1] += max(d[i][j-1][0], d[i][j-1][1]); 47 } 48 return max(d[n-1][m-1][0], d[n-1][m-1][1]); 49 } 50 51 int main() 52 { 53 while (scanf ("%d%d", &n, &m) != EOF && n){ 54 init(); 55 printf ("%d\n", DP()); 56 } 57 return 0; 58 }
------------------------------------------------------------------
现在的你,在干什么呢?
你是不是还记得,你说你想成为岩哥那样的人。
现在的你,在干什么呢?
你是不是还记得,你说你想成为岩哥那样的人。