(ACWing313)花店橱窗(动态规划+路径输出)

题目链接:313. 花店橱窗 - AcWing题库

输入样例:

3 5 
7 23 -5 -24 16
5 21 -4 10 23
-21 5 -4 -20 20

输出样例:

53
2 4 5

 题意很明确,每一行需要取一个数,且这些数出现在不同列且行数小的数所在的列数也小。

思路分析:

f[i][j]表示在1~j列中选取了i个数的合法方案的最大权值和,很显然j>=i,需要注意的一点是对于f[i][j]不一定选了第i行第j列的数,至于更新过程也比较容易,我们考虑f[i][j]的来源,第一种情况是f[i][j-1],也就是说在1~j列中选取了i个数的合法方案的最大权值和中第i行选取的数并不是第j个,而是第1~j-1个数中的一个,另一种情况是f[i-1][j-1]+a[i][j],也就是说在1~j列中选取了i个数的合法方案的最大权值和中第i行选取的数就是第j个数,这个也比较容易理解,同理需要注意的一点就是f[i-1][j-1]也并不代表我们选取了第i-1行的第j-1列的数,只要明白了这些这道题基本上就没什么了。

输出路径的时候我们只需要令path[i][j]表示第i行选取的数的位置即可,前提是j大于第i行最优答案数所在的位置,再分别根据f[i][j]的来源来更新路径,如果f[i-1][j-1]+a[i-1][j-1]>f[i][j-1],这意味着我们第i行选的数就是j,那么令path[i][j]=j即可,否则若f[i-1][j-1]+a[i-1][j-1]<=f[i][j-1](注意等号的位置不能换地方,这是由于字典序所决定的),这意味着我们第i行选的数的位置记录在了path[i][j-1]中,所以我们直接令path[i][j]=path[i][j-1]即可

然后我们直接一个while循环存下最优答案中每行选取的数的位置即可。

下面是代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
const int N=103;
int a[N][N],f[N][N],path[N][N];
int st[103],top=0;
int main()
{
	int n,m;
	cin>>n>>m;
	memset(f,-0x3f,sizeof f);
	for(int i=0;i<=m;i++)
		f[0][i]=0;
	for(int i=0;i<=n;i++)
		f[i][0]=0;
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
		scanf("%d",&a[i][j]);
	for(int i=1;i<=n;i++)
	for(int j=i;j<=m;j++)
	{
		if(j!=i)
		{
			if(f[i][j-1]>=f[i-1][j-1]+a[i][j])
			{
				f[i][j]=f[i][j-1];
				path[i][j]=path[i][j-1];
			}
			else
			{
				f[i][j]=f[i-1][j-1]+a[i][j];
				path[i][j]=j;
			}
		}
		else
		{
			f[i][j]=f[i-1][j-1]+a[i][j];
			path[i][j]=j;
		}
	}
	int ans=-0x3f3f3f3f;
	int t=0;
	for(int i=n;i<=m;i++)
	{
		if(ans<f[n][i])
		{
			ans=f[n][i];
			t=i;
		}
	}
	while(n)
	{
		st[++top]=t;
		n--;
		t=path[n][t-1];
	}
	printf("%d\n",ans);
	for(int i=top;i>=1;i--)
		printf("%d ",st[i]);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值