题意:给定一个图,在图上要求找一个最长链,使得后面一个点的度数比前一个点的度数大,问最长的长度是多少?
可以利用拓扑排序的方式进行dp,首先更新dp值全为1,然后遍历度数,每次找出最小的度数,更新完dp之后,删去这些点,再找最小的度数。。。。,最后的最大的dp值就是答案。
dp[i]代表到i点的最长的链的长度
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
const int MAXN = 1e5 + 5;
vector<int>ve[MAXN];
int deg[MAXN];
int dp[MAXN];
vector<int>ans[MAXN];
int main()
{
int n,m;
memset(deg,0,sizeof(deg));
scanf("%d %d",&n,&m);
int MIN = inf;
for(int i = 0;i < m;++i){
int x,y;
scanf("%d %d",&x,&y);
ve[x].pb(y);
ve[y].pb(x);
deg[x]++;deg[y]++;
}
int len = -1;
for(int i = 0;i < n;++i){
ans[deg[i]].pb(i);
len = max(len,deg[i]);
}
for(int i = 0;i < n;++i){
dp[i] = 1;
}
for(int i = 0;i <= len;++i){
if(ans[i].size() > 0){
for(int j = 0;j < ans[i].size();++j){
int v = ans[i][j];
for(int k = 0;k < ve[v].size();++k){
int p = ve[v][k];
if(deg[p] < deg[v])
dp[v] = max(dp[v],dp[p] + 1);
}
}
}
}
int MAX = 1;
for(int i = 0;i < n;++i){
MAX = max(MAX,dp[i]);
}
printf("%d\n",MAX);
return 0;
}
下面还有一种dp的方法,利用dfs来解决,dp[i]代表以i节点开始的最长链的长度,
dp[i] = max(dp[i],dp[k] + 1);k是i的邻接点,且度数大于i点
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
const int MAXN = 1e5 + 5;
vector<int>ve[MAXN];
int dp[MAXN];
int n,m;
int deg[MAXN];
int dfs(int id)
{
if(dp[id]) return dp[id];
int sum = 1;
int len = ve[id].size();
for(int i = 0;i < len;++i){
int v = ve[id][i];
if(deg[v] > deg[id]){
sum = max(sum,dfs(v) + 1);
}
}
dp[id] = sum;
return sum;
}
int main()
{
scanf("%d %d",&n,&m);
memset(dp,0,sizeof(dp));
memset(deg,0,sizeof(deg));
for(int i = 0;i < m;++i){
int a,b;
scanf("%d %d",&a,&b);
ve[a].pb(b);
ve[b].pb(a);
deg[a]++;deg[b]++;
}
int MAX = 1;
for(int i = 0;i < n;++i){
MAX = max(MAX,dfs(i));
}
printf("%d\n",MAX);
return 0;
}