矩阵内移动路径2

题目要求:
给定一个𝑛∗𝑚的矩阵,每个单元都有一个值,现在从左上走到右下再回到左上,中间不走重复的点,求所走单元的和的最大值。

主要思路:
本题是求从矩阵左上角走到右下角再回到左上角,该路径的最大值,并且要求中间不走重复的点。先定义一个数组a[100][100]用来存储每个单元的值。如果按照题目要求去寻找路径,走的方向是不一样的,比较难于区分是否走过重复的点,所以将该题转化为从矩阵左上角到右下角,找出两条不同的路径,使得相加得到的值最大。
所以定义一个数组f[x1][y1][x2][y2],表示第一条路走到(x1,y1),第二条路走到(x2,y2)时候的最大值。一开始我写的状态方程是f[x1][y1][x2][y2]=max(f[x1-1][y1][x2][y2], f[x1][y1-1][x2][y2],f[x1][y1][x2-1][y2],dp[x1][y1][x2][y2-1])+a[x][y],但是这种情况下还会有重复的路径存在,看了一些资料之后我知道,这样的原因是因为状态转移方程在设计的时候,没有考虑到阶段性,两条路径没有同时出发,例如,对于f[2][2][3][3],它有可能经过了f[1][1][3][3],而f[1][1][3][3]又有可能经过了f[1][1][2][2],这样,(2,2)这个坐标既出现在了第一条路里,又出现在第二条路里。经过对状态转移方程稍作改动:f[x1][y1][x2][y2]=max(f[x1-1][y1][x2-1][y2],f[x1-1][y1][x2][y2-1],f[x1][y1-1][x2-1][y2],f[x1][y1-1][x2][y2-1])+a[x1][y1]+a[x2][y2]使得此时两条路的选择是同步的,以上四个f数组分别对应了到达(x1,y1,x2,y2)的四种情况。还可以发现一个规律:对于所有步数为s可以到达的坐标,x+y=s+2。所以,当两条路同步时,有x1+y1=x2+y2,变形一下,x1+y1-x2=y2
还有一个问题,如果两条路相交后,必然会存在重复的点。如在两个交叉点之间有两条路,我们可以交换两条路,而对于两个交叉点,让其中一条路绕一下,绕过这个重复的点,这样做,不仅可以使得两条图不存在重复的点,而且值还增大了,我们也可以反推出存在两个交叉点的路必定不是我们要找的路,还有比他更大的,所以完全没有必要考虑路径的交叉情况。
通过循环调用上述状态转移方程,不断将最大值记录到f[x1][y1][x2][y2]中,因为两条路要不同,所以一条由[n-1][m]即右下角的上方,一条由[n][m-1]即右下角的左边到达右下角,最后输出f[n][m-1][n-1][m]即为两条路的相加和的最大值。

在这里插入图片描述

#include <iostream>
using namespace std;
int a[100][100]; //存储每个单元的值
int f[100][100][100][100]; //f[x1][y1][x2][y2],表示第一条路走到(x1,y1),第二条路走到(x2,y2)时候的最大值。
int max(int a,int b,int c,int d)//四个数中取最大
  {
  	if(b>a) a=b;
  	if(c>a) a=c;
  	if(d>a) a=d;
  	return a;
  }

int main()
  {
  	int n,m;
	cout<<"请输入矩阵的行数和列数:";
  	cin>>n>>m; 	
	cout<<"请输入矩阵中每个单元的值:";
  	for(int s=1;s<=n;s++)
	{
  	   for(int t=1;t<=m;t++)
	   {
  	      cin>>a[s][t];
	   }
	}
    //转移方程,找到最优解
	for(int i=1;i<=n;i++)
	   for(int j=1;j<=m;j++)
	      for(int k=1;k<=n;k++)
		     for(int l=j+1;l<=m;l++)
			    f[i][j][k][l]=max(f[i-1][j][k-1][l],f[i-1][j][k][l-1],f[i][j-1][k][l-1],f[i][j-1][k-1][l])+a[i][j]+a[k][l];//转移方程 
    cout<<"两条路的所走单元的和的最大值为:"<<f[n][m-1][n-1][m]<<endl;//目标状态,因为两条路要不同,所以一条由[n-1][m]即右下角的上方,一条由[n][m-1]即右下角的左边到达右下角 
    return 0;
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值