1.题意:给出一个图,规定每个点只能往度数比该点大的点走,问图中最长的路径长度(经过点的个数最多)是多少?
2.分析:
考虑如下情况:
(1)假如我们已经找到 2 - > 5 - > 4 - > 1是从2出发的最长路 , 那么这条路径中间经过的点的最长路径也一定在这条路径当中,因为没经过一个点,这个点总要努力试探各个方向的最长路,选定适合自己的最长路,那么也一定是前方点的最长路
(2)假如我们已经找到了 5 - > 4 -> 1的最长路,那么现在2走到5时,2的最长路 = max(dp[2],sum + dp[5]);
(3)DFS找路径同时记录最长路,动态更新,树状dp
3.代码:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 7;
struct Edge{
int to,next;
}edge[maxn*6];
int degree[maxn],head[maxn],tot;
int dp[maxn],maxx;
bool vis[maxn];//不用标记,因为只能往度数大的地方走,不可能往回走
int n,m;
void addEdge(int a,int b){//链式前向星
edge[tot].to = b;edge[tot].next = head[a];head[a] = tot++;
}
int DFS(int p){
if(dp[p])return dp[p];//该点有记录的最长路直接返回
int sum = 1;//否则当前最少一个点
for(int i = head[p];~i;i = edge[i].next){
int point = edge[i].to;
if(degree[point]>degree[p]){//度数大的地方才能走
sum = max(sum,DFS(point)+1);//原来大还是走这个点大
}
}
dp[p] = sum;//记录这点的最大值
return sum;
}
int main()
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
memset(degree,0,sizeof(degree));
memset(dp,0,sizeof(dp));
tot = maxx = 0;
for(int i = 0;i<m;i++){
int a,b;
scanf("%d%d",&a,&b);
addEdge(a,b);
addEdge(b,a);
degree[a]++;
degree[b]++;
}
for(int i = 0;i<n;i++){
maxx = max(maxx,DFS(i));//判断每一个点最长路
}
printf("%d\n",maxx);
return 0;
}