洛谷P10287 [GESP样题 七级] 最长不下降子序列
题目
传送门
题意
给定一个n 个节点 m 条边的有向无环图,其中节点的编号为1到n。对于编号为i的节点,其权值为a[i]。对于图中的一条路径,根据路径上的经过节点的先后顺序可以得到一个节点权值的序列,求图中所有可能序列中最长不下降子序列的最大长度。
思路
有向无环图
一眼拓扑排序,没什么好说的
最长不下降子序列的最大长度
一眼动态规划
动态规划实现
定义状态
我们可以定义dp[i]为以i为结尾的最长不下降子序列的最大长度,但是我们发现会TLE。这时我们观察到了数据范围1<=a[i]<=10,这不是可以成为我们状态的第二维吗?于是我们的状态为dp[i][j]是以i为结尾的权值为j的最长不下降子序列的最大长度。
转移方程
我们可以这里利用了两个转移
- 第一,我们不选择a[i],那么我们的转移方程为dp[i][j]=dp[i-1][j]
- 第二,我们选择了a[i],But我们的前提条件为a[i]>=j,那么我们就可以利用我们的二维,只用遍历到j即可,转移方程为dp[i][j]=max(dp[i][j],dp[v][j]+1),这里的v指的是我们的边的前驱
初始化
我们直接dp[i][a[i]]=1即可
拓扑排序的用途
我们每次遍历入度为0的点时,便加入我们的队列即可,每次取出我们的队头时遍历他能去的边,然后把他遍历到的边的入度减一即可,如果为0就入队
代码
高清有码(有注释)
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;//定义常量是个好习惯,复制你数错0
int n,m;//看题目解释
int dp[N][15],a[N],ru[N];//看题目解释,ru[i]是每个点的入度数
vector<int>v[N];//建图
int main(){
std::ios::sync_with_stdio(false);//关闭输入输出流
std::cin.tie(0);
std::cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=m;i++){
int u1,v1;
cin>>u1>>v1;
v[u1].push_back(v1);//建图
ru[v1]++; //入度++
}
queue<int>q;
for(int i=1;i<=n;i++){
if(ru[i]==0){
q.push(i);//寻找入度为0的点,放入队列
}
dp[i][a[i]]=1;//初始化
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=0;i<v[u].size();i++){//遍历能够到达的边
ru[v[u][i]]--;//入度--
if(ru[v[u][i]]==0){
q.push(v[u][i]);//入队列
}
for(int j=1;j<=a[v[u][i]];j++){//只用遍历小于a[i]的
dp[v[u][i]][a[v[u][i]]]=max(dp[v[u][i]][a[v[u][i]]],dp[u][j]+1);//转移方程2 ,取a[i]
}
for(int j=1;j<=10;j++){
dp[v[u][i]][j]=max(dp[v[u][i]][j],dp[u][j]);//转移方程1 ,不取a[i]
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=10;j++){
ans=max(ans,dp[i][j]);//遍历寻找最大值
}
}
cout<<ans;//输出
return 0;
}
高清无码(无注释)
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m;
int dp[N][15],a[N],ru[N];
vector<int>v[N];
int main(){
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=m;i++){
int u1,v1;
cin>>u1>>v1;
v[u1].push_back(v1);
ru[v1]++;
}
queue<int>q;
for(int i=1;i<=n;i++){
if(ru[i]==0){
q.push(i);
}
dp[i][a[i]]=1;
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=0;i<v[u].size();i++){
ru[v[u][i]]--;
if(ru[v[u][i]]==0){
q.push(v[u][i]);
}
for(int j=1;j<=a[v[u][i]];j++){
dp[v[u][i]][a[v[u][i]]]=max(dp[v[u][i]][a[v[u][i]]],dp[u][j]+1);
}
for(int j=1;j<=10;j++){
dp[v[u][i]][j]=max(dp[v[u][i]][j],dp[u][j]);
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=10;j++){
ans=max(ans,dp[i][j]);
}
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号