• VIJOS1476 旅行规划(树形Dp + DFS暴力乱搞)


    题意:

    给出一个树,树上每一条边的边权为 1,求树上所有最长链的点集并。

    细节:

    可能存在多条最长链!最长链!最长链!重要的事情说三遍

    分析:

    方法round 1:暴力乱搞Q A Q,边权为正-> d f s 解决,如何标记点集呢,只需要求出最大长度,然后在进行一次遍历,当当前长度等于最长链长的时候就返回 true,并且对沿路的节点进行标记。
    好吧这样你就成功的死亡了,还是细节最长链有多条!有多条!有多条!好吧我们再来看一张神奇的图片
    点我的最帅最美
    想象一下多条最长链一定是根所示的有一条链和一些在同方向的等长的分支组成,所以只 D F S 一次必然在同方向的分支必然不会被标记,所以只要 D F S 两次就好了。

    方法round 2:树形 Dp 个人感觉比较反人类,在记录次长和最长的链之外我们只需要在记录一个 f[u][2] 表示距离 u 最远的节点,最后只要统计某个点的最长链是否等于最长链即可。
    最后献上一波转移:
    if (f[v][0]+1!=f[u][0] || (f[v][0]+1==f[u][0] && cnt>1)) f[v][2]=max(f[u][2], f[u][0])+1;
    else f[v][2]=max(f[u][2], fu)+1;

    cnt 是某节点儿子节点数

    代码:

    Round1:
    
    #include<bits/stdc++.h>
    #define MAXN 200010
    using namespace std;
    
    vector<int> Right[MAXN];
    int n, dist[MAXN];
    bool flag[MAXN];
    
    void dfs(int u, int fa){
    	for (int i=0; i<Right[u].size(); i++){
    		int v=Right[u][i];
    		if (v==fa) continue;
    		dist[v]=dist[u]+1;
    		dfs(v, u);
    	}
    }
    
    bool solve(int u, int fa, int now, int Max){
    	for (int i=0; i<Right[u].size(); i++){
    		int v=Right[u][i];
    		if (v==fa) continue;
    		flag[u]|=solve(v, u, now+1, Max);
    	}
    	if (now==Max) {
    		flag[u]=1;
    		return flag[u];
    	}
    	else return flag[u];
    }
    
    int main(){
    	scanf("%d", &n);
    	for (int i=1, x, y; i<n; i++){
    		scanf("%d%d", &x, &y);
    		Right[x].push_back(y);
    		Right[y].push_back(x);
    	}
    	memset(dist, 0, sizeof dist);
    	dfs(0, -1);
    	int Max=0, maxnum;
    	for (int i=0; i<n; i++) 
    		if (dist[i]>Max) Max=dist[i], maxnum=i;
    	memset(dist, 0, sizeof dist);
    	dfs(maxnum, -1);
    	Max=0;
    	int Maxnum;
    	for (int i=0; i<n; i++) 
    		if (dist[i]>Max) Max=dist[i], Maxnum=i;
    	solve(maxnum, -1, 0, Max);
    	solve(Maxnum, -1, 0, Max);
    	for (int i=0; i<n; i++) 
    		if (flag[i]) printf("%d
    ", i);
    	return 0;
    }
    
    Round2:
    
    #include<bits/stdc++.h>
    #define MAXN 200010
    using namespace std;
    
    int f[MAXN][3], n;
    vector<int> Right[MAXN];
    
    void Tree_Dp(int u, int fa){
    	for (int i=0; i<Right[u].size(); i++){
    		int v=Right[u][i];
    		if (v==fa) continue;
    		Tree_Dp(v, u);
    		if (f[v][0]+1>f[u][0]) f[u][1]=f[u][0], f[u][0]=f[v][0]+1;
    			else if (f[v][0]+1>f[u][1]) f[u][1]=f[v][0]+1;
    	}
    } 
    
    void solve(int u, int fa){
    	int cnt=0;
    	for (int i=0; i<Right[u].size(); i++){
    		int v=Right[u][i];
    		if (v==fa) continue;
    		if (f[v][0]+1==f[u][0]) cnt++;
    	}
    	for (int i=0; i<Right[u].size(); i++){
    		int v=Right[u][i];
    		if (v==fa) continue;
    		if (f[v][0]+1!=f[u][0] || (f[v][0]+1==f[u][0] && cnt>1)) f[v][2]=max(f[u][2], f[u][0])+1;
    		else f[v][2]=max(f[u][2], f[u][1])+1;
    		solve(v, u);
    	}
    }
    
    int main(){
    	scanf("%d", &n);
    	for (int i=1, x, y; i<n; i++){
    		scanf("%d%d", &x, &y);
    		Right[x].push_back(y);
    		Right[y].push_back(x);
    	}
    	Tree_Dp(0, -1);
    	int Max=0;
    	for (int i=0; i<n; i++) Max=max(Max, f[i][0]+f[i][1]);
    	solve(0, -1);
    	for (int i=0; i<n; i++) 
    		if (f[i][0]+max(f[i][1], f[i][2])==Max) printf("%d
    ", i);
    	return 0;
    }
    
  • 相关阅读:
    spring cloud 之config配置
    java HTTP连接 可以结合springcloud服务发布注册
    webStrom的注册码地址
    VUE的富文本编辑器
    vue2.0对于IE9浏览器的兼容
    用花生壳代理出现Invalid Host header错误
    用于时间统计数据的SQL
    Leetcode 136. Single Number
    Leetcode 36. Valid Sudoku
    VS Code
  • 原文地址:https://www.cnblogs.com/xiannvzuimei/p/9963937.html
Copyright © 2020-2023  润新知