在动态规划(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,因为需要严格的单调递增。
分析完题目,我们来处理一些具体的代码写法。
- 在我们
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{
\newlineint h,w,num;
\newline}a[MAXN];
- 我们对
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){
\newlineif(a.w!=b.w) return a.w<b.w;
\newlineelse return a.h<b.h;}
- 同时,因为题目给出了
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;
}