List动态规划

在动态规划(dp)类型的题目中,有一类题要求我们对数列进行dp,例如求最长不下降子序列,属于比较基础的dp,现在看一道模板题:Codeforce4D
因为本题需要对一对元素进行升序排列,且物品之间顺序可以调换,我们不妨先让 w w w升序排列,注意 w w w相等时,我们应该让 h h h升序排列,排好序后,我们只需求 h h h的最长严格上升子序列即可。
对于求单元素的序列,我们有状态转移方程:
f ( i ) = m a x j < i f ( j ) + 1 ( w h e n   a [ i ] . h > a [ j ] . h ) f ( i ) = m a x i < j f ( j ) ( w h e n   a [ i ] . h < = a [ j ] . h ) f(i)=max_{j<i}f(j)+1(when~a[i].h>a[j].h)\\ f(i)=max_{i<j}f(j)(when~a[i].h<=a[j].h) f(i)=maxj<if(j)+1(when a[i].h>a[j].h)f(i)=maxi<jf(j)(when a[i].h<=a[j].h)
这里分为第 i i i个物品有没有被选中,如果能被选中,则是第一个状态转移方程;如果不能被选中,则是第二个状态转移方程,同时我们应注意到上述状态转移方程应该有 a [ i ] . w ! = a [ j ] . w a[i].w!=a[j].w a[i].w!=a[j].w,因为需要严格的单调递增。
分析完题目,我们来处理一些具体的代码写法。

  1. 在我们 s t r u c t struct struct数组 a a a的时候,应该给他三个属性, w , h , n u m w,h,num w,h,num,**我们要用 n u m num num来记录其 原始序号,因为最后输出的时候要输出其原始序号 \newline struct thing{ \newline int h,w,num; \newline }a[MAXN];
  2. 我们对 w w w进行升序排列时会用到 s o r t sort sort函数, s o r t sort sort函数可以对一个序列的元素以某种方式进行排序,其形式为 s o r t sort sort(初指针,终指针,比较函数),被排序的序列在初指针和终指针之间, s o r t sort sort根据比较函数的返回值( b o o l bool bool类型)来决定是否交换两个元素的位置,当返回值为 t r u e true true时, s o r t sort sort不会交换被比较的两个元素的位置,相反,则会交换。 \newline bool cmp(const thing &a,const thing &b){ \newline if(a.w!=b.w) return a.w<b.w; \newline else return a.h<b.h;}
  3. 同时,因为题目给出了 w , h w,h w,h的范围限制,不满足范围限制的不存入 a a a数组中即可。
    下面贴上完整代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=5e3+5;
struct thing{
	int w;
	int h;
	int num;
}a[MAXN];
int dp[MAXN];
int read(){
	int k;
	cin>>k;
	return k;
}
bool cmp(const thing &a,const thing &b){
	if(a.w!=b.w) return a.w<b.w;
	return a.h<b.h;//当w相同时,将h小的放在前面 
	}
int main(){
	int n,w0,h0;
	cin>>n>>w0>>h0;
	int cnt=0;
	for(int i=1;i<=n;i++){
		int w=read();
		int h=read();
		if(w>w0&&h>h0){
			a[++cnt].w=w;
			a[cnt].h=h;
			a[cnt].num=i;
		}
	}
	sort(a+1,a+cnt+1,cmp);
    memset(dp,0,sizeof(dp));
    dp[1]=1;
    int check=0;//检查该物品是否被选上 
	for(int i=2;i<=cnt;i++){
		for(int j=i-1;j>=1;j--){
		   dp[i]=max(dp[i],dp[j]);
		if(a[i].h>a[j].h&&a[i].w!=a[j].w){
		   if(dp[i]<dp[j]+1){
			dp[i]=dp[j]+1;
			check=1;
		   }
		   }
	    }
	    if(!check){
	    	a[i].num=0;
		}
		check=0;
	}
		if(cnt==0){
		cout<<0;
		return 0;
	}
	cout<<dp[cnt]<<endl;
	for(int i=1;i<=cnt;i++){
		if(a[i].num)
		cout<<a[i].num<<' ';
	}
	return 0;
} 
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值