dp算法总结

dp算法部分总结

个人感受:听了几次课做了几个题之后,觉得这个dp并不和之前的算法一样,是一种思想,要更加偏向于问题的分析,而代码只是表示问题解决的过程,虽然并没有做太多题,说实话,有时候根本想不出怎么进行状态转化,尽管看了题解也需要再花一些时间思考,并不容易理解透。先从简单入手,其实也是有最基本的模板类型的,比如最大上升子序列,最大公共子串等等,一些问题根本思想就是这个,只不过数据的处理要麻烦一些,比如有个题是数据的输出那个序号,还是没搞懂为什么那样做,总之,还是要继续体会,继续想,多动手写一写会比较好,有助于理解。

这类问题具体解决的时候还有个共性的东西,比如dp[i]表示前i个数据怎么样怎么样,然后再从这个具体展开 所谓的状态改变

具体的就举几个自己掌握的模板例子吧

1.最大上升子序列问题
分析:要找最大的,那就先找出以dp[i]作为结尾的上升序列,再取最大值即可

int main()
{  
 int n,sum;
 for(int i=1;i<=n;i++)
    dp[i]=1;
    for(int j=2;j<i;j++)
      if(a[j]<a[i])
        dp[i]=max(dp[i],dp[j]+1);
cout<<dp[i]<<endl;
  

2.最大公共子序列
思想:dp[i][j] 表示A的前i个 和B的前j个 相同的个数
转态转移方程:if(a[i]==b[j]) dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i][j-1],dp[i-1][j])

3.最大字段和
思想 :dp[i]表示前i个数据的字段和

#include<iostream>
using namespace std;
int main()
{
    int dp[100];
    int sum=-1;
    int a[6]={5,6,-1,5,4,-7};
    for(int i=0;i<=5;i++){
       dp[i]=max(dp[i-1]+a[i],0);
       if(dp[i]>sum) sum=dp[i];
    }
    cout<<sum<<endl;
    return 0;
}

注意一个问题 字段是连续的 序列可以不连续!

最后一个例子
有关路径输出的,脑门疼,非得用写出来才略懂里的,真的很神奇的操作,这个代码不是自己写的,搜的题解,然后扣明白的!!要掌握这种方法

#include<iostream>
#include<algorithm>
using namespace std;

struct node
{
	int w;
	int s;
	int no;
}mice[1005];

struct node2
{
	int sum=1;
	int pre=0;
}dp[1005];
bool cmp(node a, node b)
{
	if (a.w == b.w)
		return a.s > b.s;
	return a.w < b.w;
}

int main()
{
	int k = 0, max, t;
	while (cin>>mice[k].w>>mice[k].s &&mice[k].w&&mice[k].s)
	{
		mice[k].no = k + 1;
		k++;
	}
	sort(mice, mice + k, cmp);
	max = 1;
	t = 1;
	for (int i = 1; i < k; i++)
	{
		for (int j = 0; j < i; j++)
		{
			if (mice[j].s > mice[i].s&&mice[j].w < mice[i].w)//找出质量大速度小的
			{
				if (dp[i].sum < dp[j].sum + 1)//最大连续序列
				{
					dp[i].sum = dp[j].sum + 1;
					dp[i].pre = j;
				}
			}
		}
		if (dp[i].sum > max)
		{
			max = dp[i].sum;
			t = i;
		}
	}
	cout << max << endl;
	int m[1005];
	for (int i = 1; i <= max; i++)
	{
		m[i] = t;
		t = dp[t].pre;
	}
	for (int j = max; j >= 1; j--)
		cout<<mice[m[j]].no<<endl;
}

关键是路径输出 很难搞懂的地方(对我来说)


			{
				if (dp[i].sum < dp[j].sum + 1)//最大连续序列
				{
					dp[i].sum = dp[j].sum + 1;
					dp[i].pre = j;//记录所使用数据的序号
				}
			}
		}
		if (dp[i].sum > max)
		{
			max = dp[i].sum;
			t = i;//这个是最后一个的序号
		}
	}
	cout << max << endl;
	int m[1005];
	for (int i = 1; i <= max; i++)
	{
		m[i] = t;
		t = dp[t].pre;//具体为什么这么操作我也不明白,我试了试的确是这样。。。。。
	}
	for (int j = max; j >= 1; j--)
		cout<<mice[m[j]].no<<endl;
}
  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值