Gym - 101667C Game Map 树状DP

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;
}

猜你喜欢

转载自blog.csdn.net/qq_40772692/article/details/82252645