取数字问题题解

4 篇文章 0 订阅

【题目链接】

1644

【解题思路】

【方法一】

这道题看着那么小的数据范围就很像是 d f s dfs dfs,我们先考虑用 d f s dfs dfs 来做,可是普通的 d f s dfs dfs 是会超时的,我们考虑剪枝。
因为它得到的值可能会有些重复,我们可以用上以前学过的记忆化,把当前位置的值有没有算出过存起来,一次再算出这个值,直接退出。然后我们就可以愉快AC了。

【CODE】

#include<iostream>
using namespace std;
const int M=11000;
int n,m,ans;
int a[11][11];
int d[11][11][M*2];
void dfs(int x,int y,int tmp)
{
	d[x][y][tmp+M]=1;//记忆化
	if (d[1][1][M])return ;//找到就退出
	if ((x-1>0)&&!d[x-1][y][tmp-a[x-1][y]+M]) dfs(x-1,y,tmp-a[x-1][y]);
	if ((y-1>0)&&!d[x][y-1][tmp-a[x][y-1]+M]) dfs(x,y-1,tmp-a[x][y-1]);
}
int main()
{
	cin>>n>>m;
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
			cin>>a[i][j];
	ans=-1;
	for (int k=1;k<=n*m*10;k++)//最大值
	{
		dfs(n,m,k-a[n][m]);//倒着搜
		if (d[1][1][M])//第一行第一个是0,所以最后只剩一个绝对值
		{
			ans=k;
			break;
		}
	}
	cout<<ans;
	return 0;
}

【方法二】

因为只能向下或向右走,没有后效性,用 d p dp dp 也是可以的。
不过我们这个 d p dp dp 和以前的又所不同,我们以前的 d p dp dp 是存贮最优值的,而我们这个 d p dp dp 却是存下标是否存在。
d p i , j , k dp_{i,j,k} dpi,j,k 的意思是第 i i i 行第 j j j 个结果为 k k k 的存不存在。
最后输出的时候在 d p n , m , k dp_{n,m,k} dpn,m,k 中找一个最小的 k k k 输出即可,如果找不到就输出 − 1 -1 1
因为数据中有负数,我们为了防止数据越界给它的下标加上一个值保证它是正数。

【CODE】

#include<iostream>
using namespace std;
int n,m;
int Q=100;//绝对值
int d[11][11][10100];
int a[11][11];
int main()
{
	cin>>n>>m;
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
			cin>>a[i][j];
	//dp的初始化
	d[1][1][Q+a[1][1]]=1;
	for (int i=2;i<=m;i++)
		for (int j=1;j<=10100;j++)
			if (d[1][i-1][j])
				d[1][i][j+a[1][i]]=1;
	for (int i=2;i<=n;i++)
		for (int j=1;j<=10100;j++)
			if (d[i-1][1][j])
				d[i][1][j+a[i][1]]=1;
	for (int i=2;i<=n;i++)
		for (int j=2;j<=m;j++)
		{
			for (int k=1;k<=10100;k++)//枚举k的值
				if (d[i-1][j][k])//如果前一个位置的k存在,则当前位置的k+当前位置的值也一定是存在的。	
					d[i][j][k+a[i][j]]=1;
			for (int k=1;k<=10100;k++)
				if (d[i][j-1][k])//和上面同理
					d[i][j][k+a[i][j]]=1;
		}
	for (int i=Q+1;i<=10100;i++)//
	{
		if (d[n][m][i]==1)
			{
				cout<<i-Q;//减去加上的那个值
				return 0;
			}
	}
	cout<<-1;
	return 0;
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值