算法训练 传纸条  
时间限制:1.0s   内存限制:512.0MB
问题描述
  小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题。一次素质拓展活动中,班上同学安排做成一个m行n列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无法直接交谈了。幸运的是,他们可以通过传纸条来进行交流。纸条要经由许多同学传到对方手里,小渊坐在矩阵的左上角,坐标(1,1),小轩坐在矩阵的右下角,坐标(m,n)。从小渊传到小轩的纸条只可以向下或者向右传递,从小轩传给小渊的纸条只可以向上或者向左传递。
  在活动进行中,小渊希望给小轩传递一张纸条,同时希望小轩给他回复。班里每个同学都可以帮他们传递,但只会帮他们一次,也就是说如果此人在小渊递给小轩纸条的时候帮忙,那么在小轩递给小渊的时候就不会再帮忙。反之亦然。
  还有一件事情需要注意,全班每个同学愿意帮忙的好感度有高有低(注意:小渊和小轩的好心程度没有定义,输入时用0表示),可以用一个0-100的自然数来表示,数越大表示越好心。小渊和小轩希望尽可能找好心程度高的同学来帮忙传纸条,即找到来回两条传递路径,使得这两条路径上同学的好心程度只和最大。现在,请你帮助小渊和小轩找到这样的两条路径。
输入格式
  输入第一行有2个用空格隔开的整数m和n,表示班里有m行n列(1<=m,n<=50)。
  接下来的m行是一个m*n的矩阵,矩阵中第i行j列的整数表示坐在第i行j列的学生的好心程度。每行的n个整数之间用空格隔开。
输出格式
  输出一行,包含一个整数,表示来回两条路上参与传递纸条的学生的好心程度之和的最大值。
样例输入
3 3
0 3 9
2 8 5
5 7 0
样例输出
34
数据规模和约定
  30%的数据满足:1<=m,n<=10
  100%的数据满足:1<=m,n<=50
 
题目解析:
  本道题需用到的算法为动态规划
  题目中提到在 m 行 n 列且带有权值的矩阵中从(1,1)到(m,n)找一条路径,然后再从(m,n)到(1,1)找一条路径,这两天路径不能重复,即每个点只能两个人只能走一次,且不可以回退,即第一条只能向下或向右,第二条只能向上或向左。化简后可知:其实就是从(1,1)到(m,n)找两条路径,这两条路径只能向下或向右且不相交,计算出这两条路径的权值和的最大值即可。
  所以很容易构想出动态规划方程:
  两个人走,利用四维的数组 dp[x1][y1][x2][y2] 来保存路径中间过程的权值之和的最大值,其中 x1 y1 x2 y2 分别表示两个人的位置。
  每个人现在的位置都有两种可能:从他的上边或左边;两个人组合就有四种可能,因此:构造出动态规划方程(map[x][y] 表示权值,即好心程度):
dp[x1][y1][x2][y2]=max(dp[x1-1][y1][x2-1][y2],dp[x1][y1-1][x2-1][y2],dp[x1][y1-1][x2][y2-1],dp[x1-1][y1][x2][y2-1])+map[x1][y1]+map[x2][y2];
  其中 x1,x2 的取值范围为从起点到终点,即 1 ~ m,y1,y2 的取值范围为起点到终点,即 1 ~ n。
  此方程的时间复杂度为 O(n4)。因此可以进一步优化:
  假如现在是 5 x 5 的矩阵,每个人从起点走三步,会出现四种情况。

  这四种情况的坐标分别为:(0,3)(1,2) (2,1) (3,0)。通过这四个坐标,发现一个规律: 0 + 3 = 1 + 2 = 2 + 1 = 3 + 0 = 3 = k (k为走的步数)。所有,x1 + x2 = k , x2 + y2 = k。所以,y = k - x。因此,三维的动态规划方程为:
dp[k][x1][x2]=max(dp[k-1][x1][x2],dp[k-1][x1-1][x2-1],dp[k-1][x1-1][x2],dp[k-1][x1][x2-1])+map[x1][k-x1]+map[x2][k-x2];
  其中,dp[k][x1][x2] 就是四维的 dp[x1][y1][x2][y2],dp[k-1][x1][x2] 就是四维的 dp[x1][y1-1][x2][y2-1],map[x1][k-x1] 就是四维的 map[x1][y1],以此类推。
  终点的坐标为 (m-1,n-1),但是 k 不能到达终点这个位置,因为违背了题目中两个人不能重复,k 的最大情况为(m-1)+(n-1)- 1,k 在最小情况也就是 2 x 2 的矩阵中取得最小值 1,所以 k 的取值范围为 1 ~  m+n-3。x1 和 x2 的取值范围都为从起点(0,0)到最大步数 k,即 0 ~ k。
  此方程的时间复杂度为 O(n3)。因此还可以进一步优化:
  从三维的动态规划方程可以发现,前一步总是 k - 1,所以,二维的动态规划方程可以优化为:
dp[x1][x2] = max(dp[x1][x2], dp[x1 - 1][x2 - 1], dp[x1 - 1][x2], dp[x1][x2 - 1]) + map[x1][k - x1] + map[x2][k - x2];
  根据三维时的分析,两条路径都走不到终点,所以让第一个人走到终点的上方,第二个人走到终点的左方,k 的取值范围为 1 ~ (m-1)+(n-1)- 1,最终要输出的结果为 dp[m-2][m-1]。
  此方程的时间复杂度为 O(n2)。
 
示例代码1 [四维数组]:

 #include <iostream>
#include<stdio.h>
#include<cmath>
using namespace std; #define MAX_NUM 52 int map[MAX_NUM][MAX_NUM]; //好心程度 | 权值
int dp[MAX_NUM][MAX_NUM][MAX_NUM][MAX_NUM]; int maxPath(int m, int n)
{
for (int x1 = ; x1 <= m; x1++)
{
for (int y1 = ; y1 <= n; y1++)
{
for (int x2 = ; x2 <= m; x2++)
{
for (int y2 = ; y2 <= n; y2++)
{
/*
如果第一个人没有走到最后一行或最后一列,并且两个人没有重复
因为走到最后一行或最后一列,容易造成第二个人无路可走的情况
*/
if ((x1 < m || y1 < n) && x1 == x2 && y1 == y2)
{
continue;
}
dp[x1][y1][x2][y2] = max( max(dp[x1-][y1][x2-][y2], dp[x1-][y1][x2][y2-]),
max(dp[x1][y1-][x2-][y2], dp[x1][y1-][x2][y2-]))
+ map[x1][y1] + map[x2][y2];
}
}
}
}
return dp[m][n][m][n];
} int main()
{
int m, n;
scanf("%d%d", &m, &n); for (int i = ;i <= m; i++)
for (int j = ;j <= n; j++)
scanf("%d", &map[i][j]); int ans = maxPath(m, n);
printf("%d\n", ans); return ;
}
 
示例代码2 [三维数组]:

 #include<iostream>
#include<cstdio>
#include<cmath>
using namespace std; #define MAX_NUM 52 int map[MAX_NUM][MAX_NUM]; //好心程度 | 权值
int dp[MAX_NUM+MAX_NUM][MAX_NUM][MAX_NUM]; int maxPath(int m, int n)
{
for (int k = ;k <= m+n-; k++)
{
for (int x1 = ; x1 <= k; x1++)
{
for (int x2 = ; x2 <= k; x2++)
{
if (x1 == x2) //x1 == x2 相当于(x1 == x2 && y1 = y2)
{
continue;
}
dp[k][x1][x2] = max(max(dp[k-][x1][x2], dp[k-][x1-][x2-]),
max(dp[k-][x1-][x2], dp[k-][x1][x2-]))
+ map[x1][k-x1] + map[x2][k-x2];
}
}
}
return dp[m+n-][m-][m-];
} int main()
{
int m, n;
scanf("%d%d", &m, &n); for (int i = ; i < m; i++)
for (int j = ; j < n; j++)
scanf("%d", &map[i][j]); int ans = maxPath(m, n);
printf("%d\n", ans); return ;
}
示例代码3 [二维数组]:

 #include<iostream>
#include<cstdio>
#include<string.h>
#include<cmath>
using namespace std; #define MAX_NUM 52 int map[MAX_NUM][MAX_NUM]; //好心程度 | 权值
int dp[MAX_NUM][MAX_NUM]; int maxPath(int m, int n)
{
memset(dp, , sizeof(dp));
for (int k = ; k <= m+n-; k++)
{
for (int x1 = m-; x1 >= ; x1--)
{
for (int x2 = m-; x2 > x1; x2--)
{
if ( k >= x1 && k >= x2) //x + y = k,当k >= x时,说明还在矩阵范围之内
{
dp[x1][x2] = max(max(dp[x1][x2], dp[x1-][x2-]),
max(dp[x1-][x2], dp[x1][x2-]))
+ map[x1][k-x1] + map[x2][k-x2];
}
}
}
}
return dp[m-][m-];
} int main()
{
int m, n;
scanf("%d %d", &m, &n); for (int i = ;i < m; i++)
for (int j = ; j < n; j++)
scanf("%d", &map[i][j]); int ans = maxPath(m, n);
printf("%d\n", ans); return ;
}
 

蓝桥杯 算法训练 ALGO-36 传纸条的更多相关文章

  1. Java实现 蓝桥杯 算法训练 猴子吃包子(暴力)

    试题 算法训练 猴子吃包子 问题描述 从前,有一只吃包子很厉害的猴子,它可以吃无数个包子,但是,它吃不同的包子速度也不同:肉包每秒钟吃x个:韭菜包每秒钟吃y个:没有馅的包子每秒钟吃z个:现在有x1个肉 ...

  2. Java实现蓝桥杯 算法训练 大等于n的最小完全平方数

    试题 算法训练 大等于n的最小完全平方数 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 输出大等于n的最小的完全平方数. 若一个数能表示成某个自然数的平方的形式,则称这个数为完全平 ...

  3. 蓝桥杯算法训练 java算法 表达式求值

    问题描述 输入一个只包含加减乖除和括号的合法表达式,求表达式的值.其中除表示整除. 输入格式 输入一行,包含一个表达式. 输出格式 输出这个表达式的值. 样例输入 1-2+3*(4-5) 样例输出 - ...

  4. 蓝桥杯 算法训练 ALGO-114 黑白无常

    算法训练 黑白无常   时间限制:1.0s   内存限制:256.0MB 问题描述 某寝室的同学们在学术完之后准备玩一个游戏:游戏是这样的,每个人头上都被贴了一张白色或者黑色的纸,现在每个人都会说一句 ...

  5. java实现 蓝桥杯 算法训练 Password Suspects

    问题描述 在年轻的时候,我们故事中的英雄--国王 Copa--他的私人数据并不是完全安全地隐蔽.对他来说是,这不可接受的.因此,他发明了一种密码,好记又难以破解.后来,他才知道这种密码是一个长度为奇数 ...

  6. 蓝桥杯 算法训练 Torry的困惑(基本型)(水题,筛法求素数)

    算法训练 Torry的困惑(基本型) 时间限制:1.0s   内存限制:512.0MB      问题描述 Torry从小喜爱数学.一天,老师告诉他,像2.3.5.7……这样的数叫做质数.Torry突 ...

  7. 蓝桥杯 算法训练 区间k大数查询(水题)

    算法训练 区间k大数查询 时间限制:1.0s   内存限制:256.0MB 问题描述 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个. 输入格式 第一行包含一个数n,表示序列长度. ...

  8. 蓝桥杯--算法训练 区间k大数查询

                                                                                 算法训练 区间k大数查询   时间限制:1.0 ...

  9. 蓝桥杯 算法训练 ALGO-116 最大的算式

    算法训练 最大的算式   时间限制:1.0s   内存限制:256.0MB 问题描述 题目很简单,给出N个数字,不改变它们的相对位置,在中间加入K个乘号和N-K-1个加号,(括号随便加)使最终结果尽量 ...

随机推荐

  1. AIDL与Binder的区别

    Binder是一个远程对象的基础类,核心部分是远程调用机制,这部分是由IBinder定义的. 它是对IBinder类的实现,其中IBinder类提供了这样一个类的标准的本地化实现方式. 大多数开发者不 ...

  2. Permutations,全排列

    问题描述:给定一个数组,数字中数字不重复,求所有全排列. 算法分析:可以用交换递归法,也可以用插入法. 递归法:例如,123,先把1和1交换,然后递归全排列2和3,然后再把1和1换回来.1和2交换,全 ...

  3. scala学习手记39 - 模式匹配

    在java中有switch/case这样的模式匹配语句,可以匹配的类型包括int,byte,char,short, enum,在java8又支持了字符串. 在scala中也有类似的模式匹配语句,即ma ...

  4. EF6 Code First 系列 (四):SQLite的DropCreateDatabaseIfModelChanges和乐观并发控制

    没什么好说的,能支持DropCreateDatabaseIfModelChanges和RowVersion的Sqlite谁都想要.EntityFramework7正在添加对Sqlite的支持,虽然EF ...

  5. Linux软件安装-----apache安装

    一. ./configure --prefix=/usr/local/http2 \ --enable-modules=all \ --enble-mods-shared=all \ 开启模块共享: ...

  6. 处理跨线程操作问题(使用Action和delegate或lambda表达式)

    方法A: Action f = () =>                    {                       txtProcess.Text = "开始更新程序.. ...

  7. require.js资料

    1.http://www.ruanyifeng.com/blog/2012/11/require_js.html?bsh_bid=230697246 (require.js的用法) 2.http:// ...

  8. 【zzulioj-2115】乘积最大(区间dp)

    题目描述 今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年.在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得 ...

  9. 【Wannafly挑战赛10 - B】小H和密码(DP)

    试题链接:https://www.nowcoder.com/acm/contest/72/B 题目描述     小H在击败怪兽后,被一个密码锁挡住了去路     密码锁由N个转盘组成,编号为1~N,每 ...

  10. ROS新版本Lunar Loggerhead

    参考链接: 1 http://wiki.ros.org/lunar 2 http://wiki.ros.org/lunar/Installation 3 http://docs.ros.org/ 4  ...