Description

有一块地被划分成了n*m个区域,在一些区域里有垃圾要拾捡。
现在科研人员开发了一个能捡垃圾的机器人,机器人每一次都可以移动一个区域的距离。
假设机器人从最左上区域出发,他每次只能向右或者向下走。
每次他到达一个点,就会自动把这个点内的垃圾拾掉。
  问:该机器人最多能够拾多少垃圾?
  在最多情况下,有多少种方案?

Input

输入文件的第一行为两个整数n和m;
  接下来有一个n*m的01矩阵。
矩阵中的第i行j列的数字a[i][j]=0表示为空地。
a[i][j]=1表示为垃圾。

Output

输出两行,第一行为一个数字表示最多拾到的垃圾,第二行为一个数字表示在最多情况下,有多少种方案。

Sample Input

3 3
100
000
010

Sample Output

2
3

今天也是菜得水3级题的一天呢

因为机器人只能向下和向右走,满足无后效性。

所以我们考虑用DP作答。

首先,从输入上就有那么一个小小的坑就只有我觉得是坑吧,请大家研究一下矩阵的输入。

科科,是没有空格的。

所以我们要用string或者char数组来读入~

接着分析题意。

对于题目中的人工智障机器人,它到一个点的路径只有两
种:从上来或者从左来。

也就是说,对于题目中的点a[i][j],它只可能源于点a[i-1][j]点a[i][j-1]

这点理清了,下面就可以顺理成章地理解了。

一:求最多捡到的垃圾

我们可以用f[i][j]来统计捡到的最多垃圾数。由加法原理得出,f[i][j]=f[i-1][j]+f[i][j-1]

实现代码:

//DP求最多拾到的垃圾 
for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
		f[i][j]=max(f[i-1][j],f[i][j-1])+a[i][j];

这样下来,f[n][m]就是到达终点时捡到的最多垃圾数。即我们要的答案。

二:求在最多情况下,有多少种方案?

我们可以用q[i][j]来统计f最大时的方案数。

可得**有q[i][j]=q[i-1][j]C1+q[i][j-1]C2。

其中,若f[i-1][j]+a[i][j]==f[i][j],则C1=1,反之为0

若f[i][j-1]+a[i][j]==f[i][j],则C2=1,反之为0;

但是这样做还有一个问题:边界值的问题。

对于矩阵来说,最上和最右的点,是一定可以到达的。所以,我们可以把它们的初值赋为1。

这样一来,我们的计算式子不仅有了初始值,还没有了越界的漏洞。

实现代码:

//DP求路径数 
for(int i=1;i<=n;i++)
{
	q[1][i]=1;
	q[i][1]=1;		
}
//边界赋初值 
for(int i=2;i<=n;i++)
	for(int j=2;j<=m;j++)
	{
		long long C1,C2;
		if(f[i-1][j]+a[i][j]==f[i][j])
			C1=1;
		else C1=0;
		if(f[i][j-1]+a[i][j]==f[i][j])
			C2=1;
		else C2=0;
		q[i][j]+=q[i-1][j]*C1+q[i][j-1]*C2;
	}

似乎 一切都功德圆满了。

等等,你有看到窝的加粗嘛?

当初自信的可怜的continue就是这样WA的。。。。

一群乐于助蒻的大佬指导下,窝当时整个人就一懵的。

没错,本题最重要的部分不在前面。

其实,最重要的是

开 long long 。 。 。 。 。

惊不惊喜?

完整代码:

#include <iostream>
#include <string>

#define maxn 105
using namespace std;

string s[maxn];
long long a[maxn][maxn]; //a数组表示矩阵 
long long f[maxn][maxn]; //f数组表示当前捡的最多垃圾数 
long long q[maxn][maxn]; //g数组表示f最大时的方案数 

int main()
{
	long long n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>s[i];
		for(int j=1;j<=m;j++)
			a[i][j]=s[i][j-1]-'0';	
	}

	//DP求最多拾到的垃圾 
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			f[i][j]=max(f[i-1][j],f[i][j-1])+a[i][j];
	cout<<f[n][m]<<endl;
	
	//DP求路径数 
	for(int i=1;i<=n;i++)
	{
		q[1][i]=1;
		q[i][1]=1;		
	}
	//边界赋初值 
	for(int i=2;i<=n;i++)
		for(int j=2;j<=m;j++)
		{
			long long C1,C2;
			if(f[i-1][j]+a[i][j]==f[i][j])
				C1=1;
			else C1=0;
			if(f[i][j-1]+a[i][j]==f[i][j])
				C2=1;
			else C2=0;
			q[i][j]+=q[i-1][j]*C1+q[i][j-1]*C2;
		}
	cout<<q[n][m]<<endl;
	return 0;
}


QAQ求点赞

前往洛谷博客体验更佳:传送门


版权声明:本文为Like_Ginger原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/Like_Ginger/article/details/104283103