uva 1366(dp)

题意:有一个n*m的格子,每个格子里有A矿和B矿,A矿必须由右向左运输,B矿必须由下向上运输,给出两种矿在格子内的数量,挖矿人在每个格子里只能选一种矿挖,而且在格子内建运输管道不能拐弯或间断且都能通到格子外面。问最后能收集到的矿的总数最多多少。

题解:f[i][j][k]表示在前i行前j列第i行第j列挖k矿的最大数量,那么分两种情况

(1)第i行第j列挖A矿,那么(i,j)一定左边全是A矿,(i,j)上面可以是A也可以是B

f[i][j][0] = max(f[i - 1][j][0], f[i - 1][j][1]) + sumA[i][j]

(2)第i行第j列挖B矿,那么(i,j)一定上边全是B矿,(i,j)上面可以是A也可以是B

f[i][j][1] = max(f[i][j - 1][0], f[i][j - 1][1]) + sumB[i][j]

结果是max(f[n][m][0], f[n][m][1])

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 505;
int n, m, A[N][N], B[N][N], sumA[N][N], sumB[N][N];
int f[N][N][2];

int main() {
    while (scanf("%d%d", &n, &m) == 2 && n + m) {
        memset(f, 0, sizeof(f));
        memset(sumA, 0, sizeof(sumA));
        memset(sumB, 0, sizeof(sumB));
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++) {
                scanf("%d", &A[i][j]);
                sumA[i][j] = sumA[i][j - 1] + A[i][j];
            }
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                scanf("%d", &B[i][j]);
        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= n; j++)
                sumB[j][i] = sumB[j - 1][i] + B[j][i];
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++) {
                f[i][j][0] = max(f[i - 1][j][0], f[i - 1][j][1]) + sumA[i][j];
                f[i][j][1] = max(f[i][j - 1][0], f[i][j - 1][1]) + sumB[i][j];
            }
        printf("%d\n", max(f[n][m][0], f[n][m][1]));
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-12 17:05:06

uva 1366(dp)的相关文章

UVa 1366 DP Martian Mining

网上的题解几乎都是一样的: d(i, j, 0)表示前i行前j列,第(i, j)个格子向左运输能得到的最大值. d(i, j, 1)是第(i, j)个格子向上运输能得到的最大值. 但是有一个很关键的问题没有解释: 某个格子中的A矿或者B矿一定有其中一种能够运出来吗?有没有可能这个格子没有修建管道,仅仅是为了给其他管道让路,使得总体取得最大值呢? 从题解的状态转移方程上来看,不会的. 自己YY了好久,也没有想到一个能严格证明的方法.. 1 #include <iostream> 2 #inclu

递推DP UVA 1366 Martian Mining

题目传送门 1 /* 2 题意:抽象一点就是给两个矩阵,重叠的(就是两者选择其一),两种铺路:从右到左和从下到上,中途不能转弯, 3 到达边界后把沿途路上的权值相加求和使最大 4 DP:这是道递推题,首先我题目看了老半天,看懂后写出前缀和又不知道该如何定义状态好,写不出状态转移方程,太弱了. 5 dp[i][j]表示以(i, j)为右下角时求得的最大值,状态转移方程:dp[i][j] = max (dp[i-1][j] + sum1[i][j], dp[i][j-1] + sum2[i][j])

UVA 1366 九 Martian Mining

Martian Mining Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVA 1366 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 6 int dp[505][505][3]; 7

uva 1401 dp+Trie

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=&problem=4147 题意:给定一个字符串,以及若干单词,求有几种方式能用单词组成字符串 我先是dp方程推得有问题不知怎么修改搞得卡了很久,然后就是数组开得太小一直RE trie数组大小=单词个数*单词长度  dp[i]为以str[i]开头的后缀的ans,dp[i]=segma(

UVA - 1366 Martian Mining 三维dp

题目大意:在一个n * m的格子上有两种矿物.A矿只能从右往左运输,B矿只能从下往上运输,现在要求你在这格子上铺设管道(管道不能中断或者拐弯),用管道来运输A矿和B矿,使得运输的A矿和B矿的和最大 解题思路:设dp[i][j][0]为以(i,j)为矩阵的右下角,铺设从右往左的管道所能运输的最大值,那么第i行的第1列到第j列只能铺设从右往左的管道,所以dp[i][j][0] = max(dp[i-1][j][0],dp[i-1][j][1]) + A[i][j] 设dp[i][j][1]为以(i,

uva 1291 dp

UVA 1291 - Dance Dance Revolution 有一个跳舞机.原点为0,有四个方向,上左下右,分别标成(1234),初始玩家两只脚站在 0 位置,跳舞机会给出一串数字,玩家要按照顺序踩下四个方向的数字.移动脚会消耗玩家的能量,从0位置移动到四个方向消耗2点能量,从一个方向移动到另一个相邻的方向消耗3点能量,从一个方向移动到相反方向消耗4点能量,原点踩一下消耗1点能量.问你踩出这串数子最少要花多少能量. 根据能量消耗关系,我们可以发现当前两只脚踩的方向才是重点.然而要记录两只脚

uva 1424 dp

UVA 1424 - Salesmen 给出一副图,并且给出nhn走过的路径记入,路径可能是错的,问最少修改几个地方可以使得路径是正确的. dp[i][j] 表示修改第i个位置为j点的前i个位置的最小修改次数. dp[i][j] = min(dp[i-1][k] + (j == a[i])); {w[k][j] == true 即存在路径k~j} 然后再最后一个点找一个最小值. #include <cstdio> #include <cstring> #include <io

uva 10534 dp

UVA 10534 - Wavio Sequence 定义一种 Wavio 的序列.其长度为2*n+1,前n+1严格递增,后n+1个严格递减. 求在给的序列中找一个最长的 Wavio 子序列.输出长度. 正向LIS求出每个点以该点为结尾的最长上升子序列长度p[i],然后反向LIS求出以该点位开头的最长递减子序列长度q[i]. 然后枚举 Wavio 子序列的中点,该店的 Wavio 长度为 2 * min(p[i], q[i]) - 1; #include <cstdio> #include &

UVA 147- Dollars(dp之子集和问题)

题目地址:UVA 147 题意:给定11种面值分别为100元, 50元, 20元, 10元, and 5元 and 2元, 1元, 50分, 20分, 10分 and 5分的钱,现在给定一个钱数,求出可以组成的种类数. 思路:子集和问题:S={ x1 , x2 ,-, xn }是一个正整数的集合,c是一个正整数.子集和问题判定是否存在S的一个子集S1,使得s1中的各元素之和等于c. 最突出的事例就是硬币计数问题:设c(i,j)是a1,a2--ai中包含ai且数和为j的方案数,显然目标是求c(n,