POJ-2948 Martian Mining 动态规划

详见代码:

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

int N, M, dp[505][505];
int row[505][505], col[505][505];

/*
题意:给定一个矩阵,矩阵中的每一个点都有两种矿产,A矿产只能够运送到上面去,B矿产只能
     够运送到左边去,现在要在每个点都设置一个传送带传送带共有两种,一种是往上,一种
     是往左,每个格子只能够做一个选择,问如何安排这些传送带使得整个的传输带上能够运
     抵目的地的矿产最多.
     
解法:这题拥有这样一个性质.由于每当一个点被选取后,如果这个点是选择往上走的话,那么
     这个点的这一列上面的点就一定会全部选取,如果这个点是往左走的话,那么该点的左
     边同一行的点也应该计算在内
     设 dp[i][j]表示子矩阵(1, 1) 到 (i, j)的最大传输值,那么有动态规划方程:
     dp[i][j] = max(col[i][j]+dp[i][j-1], row[i][j]+dp[i-1][j])
     其中col[i][j]表示第j列从第1行到第i行的和; row[i][j]表示第i行1到j列的和
     该方程说明了一个事实就是对于当前点是否选择是影响整个这一行或者是这一列的
     除此之外,对其他地方并无影响 
*/

int DP() {
    for (int i = 1; i <= N; ++i) {
        for (int j = 1; j <= M; ++j) {
            dp[i][j] = max(col[i][j]+dp[i][j-1], row[i][j]+dp[i-1][j]);
        }
    }
    return dp[N][M];
}

int main() {
    while (scanf("%d %d", &N, &M), N|M) {
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= M; ++j) { // 该矩阵中的矿产需要运送到左边去
                scanf("%d", &row[i][j]);
                row[i][j] += row[i][j-1];
            }
        }
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= N; ++j) {
                scanf("%d", &col[i][j]);
                col[i][j] += col[i-1][j];
            }
        }
        printf("%d\n", DP());
    }
    return 0;    
}

 

posted @ 2013-01-14 20:11  沐阳  阅读(541)  评论(0编辑  收藏  举报