题目来源:天梯赛训练题
在一个m行n列方格矩阵中,每一个方格内摆放着价值不等的宝贝(价值可正可负),让小明感到好奇的是,从左上角到达右下角的所有可能路线中,能捡到宝贝的价值总和最大是多少?而且这种达到最大值的路线 又有多少条?【注意:只能从一个格子向下或向右走到相邻格子,并且走到的格子宝贝一定会被捡起。】
输入格式:
第一行为整数m,n(均不大于100),下一行开始会有一个m行n列的整数方阵,对应方格矩阵中的宝贝价值(这些值的绝对值都不超过500)。
输出格式:
单独一行输出2个整数,分别为能捡到宝贝价值总和的最大值和达到最大值的路线数量,2个整数间隔一个空格。
样例">输入样例:
在这里给出一组输入。例如:
4 5
2 -1 6 -2 9
-3 2 5 -5 1
5 8 3 -2 4
5 2 8 -4 7
输出样例:
对应的输出为:
26 3
题意:
有一个m行n列的矩阵,计算从左上角方格(0,0)到右下角方格(m-1,n-1)的所有路径中,路径上方格中数字的和最大值是多少,并求最大和值的路径数量。
思路:
1. 先使用dp[][]数组来计算每一步的最大值,以及最大和值;
2. 使用dfs或bfs进行遍历即可,遍历到终点时记录最大和值出现的次数即可。在某个点遍历前,不仅要判断边界条件,还要判断该点遍历是否可以得到该步的最大值,否则则考虑下一个点。 否则dfs会超时,而bfs会内存超限。
//L3-3 寻宝路线
#include <iostream>
using namespace std;
#define N 100
#include <queue>
int n,m;
int a[N][N];
int dp[N][N];
int ma = -100000000; //记录最大值
int c=0; //最大值的个数
int dx[]={0,1};
int dy[]={1,0};
void dfs(int x,int y,int sum) //dfs
{
sum+=a[x][y];
if(x==n-1&&y==m-1) //到达终点
{
if(ma==sum)
c++;
return ;
}
for(int i=0;i<2;i++)
{
int newX=x+dx[i];
int newY=y+dy[i];
//递归时既要考虑范围还要考虑是否可能为最大路径,有一点不是在最大路径上,则忽略该路径
if(newX<n&&newY<m&&sum+a[newX][newY]==dp[newX][newY]) //重点
dfs(newX,newY,sum); //向下或右走
}
}
void bfs(int x,int y) //bfs
{
queue<pair<int,int>> qe;
queue<int> value;
qe.push({x,y});
value.push(a[x][y]);
int val,newX,newY,i;
while(!qe.empty())
{
x=qe.front().first;
y=qe.front().second;
val=value.front();
qe.pop();
value.pop();
if(x==n-1&&y==m-1) //到达右下角
{
if(val==ma)
c++;
continue;
}
for(i=0;i<2;i++)
{
newX=x+dx[i];
newY=y+dy[i];
if(newX<n&&newY<m&&val+a[newX][newY]==dp[newX][newY]) //重点,边界判断 + 路径判断
{
qe.push({newX,newY});
value.push(val+a[newX][newY]);
}
}
}
}
int mafind() //找最大值
{
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(i==0&&j==0)
dp[i][j]=a[i][j];
else if(j==0)
dp[i][j]=dp[i-1][j]+a[i][j];
else if(i==0)
dp[i][j]=dp[i][j-1]+a[i][j];
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1])+a[i][j];
}
}
return dp[n-1][m-1];
}
int main()
{
cin>>n>>m;
int i,j;
for(i=0;i<n;i++) //输入
for(j=0;j<m;j++)
cin>>a[i][j];
ma=mafind(); //找最大值
// dfs(0,0,0); //使用dfs进行深度遍历
bfs(0,0); //bfs也可以做
cout<<ma<<" "<<c<<endl; //输出
return 0;
}