zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    pandas 生成excel
    身份证校验规则
    css 模态框
    python3 打开MySQL时:RuntimeError: 'cryptography' package is required for sha256_password or caching_sha2_password auth methods 报错
    selenium元素定位
    LR的基本知识
    python3的编码报错解决办法
    MySQL的简单条件判断语句
    Java判断一个字符串中包含另一字符串
    使用线程池获取执行结果,CountDownLatch+ThreadPool,FutureTask+ThreadPool 并比较
  • 原文地址:https://www.cnblogs.com/xiannvzuimei/p/9963937.html
Copyright © 2011-2022 走看看