61计蒜客 动态规划基础 蒜头君的城堡之旅

蒜国地域是一个 n 行 m 列的矩阵,下标均从 1 开始。蒜国有个美丽的城堡,在坐标 (n,m) 上,蒜头君在坐标 (1,1) 的位置上。蒜头君打算出发去城堡游玩,游玩结束后返回到起点。在出发去城堡的路上,蒜头君只会选择往下或者往右走,而在返回的路上,蒜头君只会选择往上或者往左走,每次只能走一格。已知每个格子上都有一定数量的蒜味可乐,每个格子至多经过一次。

现在蒜头君请你来帮他计算一下,如何计划来回行程,可以收集到最多的蒜味可乐。

输入格式

第一行输入两个整数 n,m(1≤n,m≤50),表示蒜国是一个 n 行 m 列的矩阵。

接下来输入 n 行,每行输入 m 个整数,代表一个 n×m 的矩阵,每个整数代表对应位置上的蒜味可乐数量,每行的每两个整数之间用一个空格隔开。其中蒜头君的位置和城堡的位置上没有蒜味可乐,用 0 表示,其余位置上的整数范围在 [1,100] 内。

输出格式

输出一行,输出一个整数,表示蒜头君在来回路上能收集到的蒜味可乐的最大值。

样例输入

3 3

0 2 9

4 8 6

2 7 0

样例输出

36

分析:

(可以理解为从起点出发的不相交的两条路径)

首先,要注意一个问题:不能先算出去的最大值,再算返回的最大值。这样可能导致只保证了去的最大值,但没有保证来回之和的最大值。也就是说,来回的优先级是相同的,但是如果先算去路的最大值就会使得去的优先级高于回的优先级。

容易注意到本题的范围不大,所以可以用一个四维数组: f[i][j][k][l] 来表示路径1走到 [i][j] 和路径2走到 [k][l] 的和的最优值。

其中,因为走的步数相同,所以 i+j=k+l (可以利用这个等式来把空间和时间复杂度降一级),不难想到只要当前一步的两条路径没有走到用一个点,两条路径就不会相交(如果相交,重叠部分的可乐只能领取一次,就不是最优情况)。

最后就不难写出动规方程:  f[i][j][k][l] = max(max(f[i-1][j][k-1][l], f[i][j-1][k-1][l]), max(f[i-1][j][k][l-1], f[i][j-1][k][l-1]))+map[i][j]+map[k][l]; 其中第一部分是求两个路径当前点的两个前趋情况的和的最大值(一共是 2×2 四种情况,所以用了一个 max 套两个 max)。

最最后,因为两条路径在终点还是会交于一点,所以千万不能输出 f[n][m][n][m] ,应该输出 f[n-1][m][n][m-1] 。

标程:

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstring>
 4 using namespace std;
 5 int n,m,map[55][55],f[55][55][55][55];
 6 int main()
 7 {
 8     memset(f,0,sizeof(f));
 9     cin >> n >> m;
10     for (int i=1; i<=n; i++)
11     {
12         for (int j=1; j<=m; j++)
13         {
14             cin >> map[i][j];
15         }
16     }
17     for (int i=1; i<=n; i++)
18     {
19         for (int j=1; j<=m; j++)
20         {
21             for (int k=1; k<=n; k++)
22             {
23                 for (int l=1; l<=m; l++)
24                 {
25                     if (i+j!=k+l)
26                         continue;
27                     if (i==k && j==l)
28                         continue;
29                     f[i][j][k][l] = max(max(f[i-1][j][k-1][l], f[i][j-1][k-1][l]), max(f[i-1][j][k][l-1], f[i][j-1][k][l-1]))
30                     +map[i][j]+map[k][l];
31                 }
32             }
33         }
34     }
35     cout << f[n-1][m][n][m-1] << endl;
36     return 0;
37 }

原文地址:https://www.cnblogs.com/passion-sky/p/8490088.html

时间: 2024-08-24 23:46:28

61计蒜客 动态规划基础 蒜头君的城堡之旅的相关文章

【计蒜客习题】蒜头君运送宝藏

!!!原来LCA的题可以出的这么难,完了这还属于水题?! 先来解释一下题意,有N个城市,在这N城市之间有M条边(不一定每个城市都有边).我们的任务是找出给定两个点之间路径上的最小边权,使得这个最小边权尽量大.一开始我很纳闷,这和LCA有什么关系呢,怎么和最大流有点像.冥思苦想(看了别人的想法)之后,哦,原来是最大生成树+LCA...因为是最大生成树,可以使得任意两点间路径上的最大边权最大(再连上较小的会成环).这样问题就变成了找树上两点间路径上的最小边权,显然可以利用LCA,这是他十分经典的应用

【计蒜客习题】 蒜头君的猜想(埃氏筛)

解题思路: 从1到n将所有数筛一遍,枚举加数,如果这两个加数都是质数,那么方案数加1. AC代码: 1 #include<cstdio> 2 3 using namespace std; 4 5 int n,ans; 6 bool vis[8000001]; 7 8 int main() 9 { 10 scanf("%d",&n); 11 for(int i = 2;i * i <= n; i++) 12 if(!vis[i]) { 13 for(int j

蒜头君的城堡之旅(动态规划)

题目: 蒜国地域是一个 n 行 m 列的矩阵,下标均从 1 开始.蒜国有个美丽的城堡,在坐标 (n,m) 上,蒜头君在坐标 (1,1) 的位置上.蒜头君打算出发去城堡游玩,游玩结束后返回到起点.在出发去城堡的路上,蒜头君只会选择往下或者往右走,而在返回的路上,蒜头君只会选择往上或者往左走,每次只能走一格.已知每个格子上都有一定数量的蒜味可乐,每个格子至多经过一次. 现在蒜头君请你来帮他计算一下,如何计划来回行程,可以收集到最多的蒜味可乐. 输入格式 第一行输入两个整数 n,m(1≤n,m≤50)

计蒜客普及组模拟赛

今天没事闲的看到计蒜客有个普及组模拟赛,就当练了练手去打了,成绩低的可怜...400分崩成280分AK梦想化作泡影 第一题 同学的爱好 链接:https://nanti.jisuanke.com/t/17291 小学应用题难度?大概画个图就能懂,把每个部分都标上号,算出a,b,c,d,e,f的部分,进行运算就行了. 不多解释了,直接上代码 #include<iostream> #include<cstdio> #include<algorithm> #include&l

计蒜客 无脑博士和他的试管们

无脑博士有三个容量分别是A,B,C升的试管,A,B,C分别是三个从1到20的整数,最初,A和B试管都是空的,而C试管是装满硫酸铜溶液的.有时,无脑博士把硫酸铜溶液从一个试管倒到另一个试管中,直到被灌试管装满或原试管空了.当然每一次灌注都是完全的.由于无脑博士天天这么折腾,早已熟练,溶液在倒的过程中不会有丢失. 写一个程序去帮助无脑博士找出当A是个是空的时候,C试管中硫酸铜溶液所剩量的所有可能性. 输入包括一行,为空格分隔开的三个数,分别为整数A,B和C. 输出包括一行,升序地列出当A试管是空的时

计蒜客 作弊揭发者(string的应用)

鉴于我市拥堵的交通状况,市政交管部门经过听证决定在道路两侧安置自动停车收费系统.当车辆驶入车位,系统会通过配有的摄像头拍摄车辆画面,通过识别车牌上的数字.字母序列识别车牌,通过连接车管所车辆信息数据库确认车辆,进行扣费. 斗智斗勇的好戏一般从此处展开… 一些车主通过在停车时遮挡车牌上的一个或多个数字.字母序列,来阻碍识别系统的识别工作,以此逃避停车费用的缴纳. 车主这简直是用轻轻的一挡搞出来一个世界难题有木有?!管理是一方面,技术解决才是王道啊. 这么难的项目不得不交给计蒜客实验室了.D 神负责

简单斐波那契——计蒜客(4)

题目来自“计蒜客”第4题. 解算法题之前,务必先写出与之对应的数学表达式,用于描述算法. 数学描述如图: 根据“数学描述“,写出代码如下: #include <stdio.h> int main() { int N =0 ; scanf("%d", &N); int i, fn1 = 1, fn2 = 0, fn; switch(N) { case 0: printf("0"); break; case 1: printf("1&quo

计蒜客 删除字母&#39;c&#39;

删除字母'c' 右侧的程序实现的功能是从字符串s中删除所有的小写字母c,请改正程序错误的地方. 注意:main函数不可以改动,程序结构也不能修改. 很简单的哦,加油吧- 样例输入 abccabcn 样例输出 ababn 1 #include <stdio.h> 2 3 #define N 1024 4 5 void del(char *s) 6 { 7 int i, j; 8 for(i = j = 0; s[i] != '\0'; i++) 9 { 10 if(s[i] != 'c') 11

计蒜客 教科书般的亵渎

Description: 环境里有 nn 个怪物,他们的生命值用一个正整数表示.现在,你可以使用两种魔法,对怪物进行攻击.当怪物的生命值小于等于 00 时,他便被消灭了. 魔法箭,对摸个生物造成 kk 点伤害,对一个生物最多使用一次,但没有使用次数限制. 亵渎,对所有生物造成一点伤害,如果杀死了某个生物,则继续自动重新使用该法术.只能主动使用一次,且必须最后使用. 请问,最多能消灭多少个怪物?亵渎法术最多能释放几次? Input: 第一行两个整数 nn 和 kk ,表示怪物的数量和法术的伤害.第