zoukankan      html  css  js  c++  java
  • 牛客OI周赛15-提高组 环球旅行

    https://ac.nowcoder.com/acm/contest/4912/A

    过这个题有个前提,需要知道删除哪条边-------必须是直径上的边

    为什么?

    如果不删直径上的边答案就不可能减少了,建议多画画试一下

    抓住直径两端s和t开始树形DP,

    具体看代码吧

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e6 + 77;
    ll cns[maxn];
    struct Node {	
    	int to;
    	ll len;
    	int nxt;
    }G[maxn * 2];
    int head[maxn];
    int z;
    void add(int be, int en,ll len) {
    	G[++z].to = en;
    	G[z].len = len;
    	G[z].nxt = head[be];
    	head[be] = z;
    }
    int n;
    ll cs = 0;
    int s, t, fa[maxn];
    int dfs(int x, int f, int d) {
    	if (cs < d) {
    		cs = d;
    		s = x;
    	}
    	for (int i = head[x]; i; i = G[i].nxt) {
    		int p = G[i].to;
    		if (p == f) continue;
    		dfs(p, x, d + G[i].len);
    	}
    	return 0;
    }
    //-----------------------------------------------------------------------------------------------------------算直径的部分
    int son[maxn];//长儿子
    ll dp[maxn];//直径
    ll dp1[maxn];
    ll dep[maxn];//子树到根的最长路
    
    int dfs1(int x, int f) {
    	ll s = 0;
    	fa[x] = f;
    
    	for (int i = head[x]; i; i = G[i].nxt) {//先找个最长边
    		int p = G[i].to;
    		ll ln = G[i].len;
    		if (p == f) continue;
    		dfs1(p, x);
    		dp[x] = max(dp[x], dp[p]);//或许子树的直径不过根
    		if (s < dep[p] + ln) {
    			s = dep[p] + ln;
    			son[x] = p;
    			dep[x] = s;
    		}
    	}
    	for (int i = head[x]; i; i = G[i].nxt) {//再算子树直径
    		int p = G[i].to;
    		ll ln = G[i].len;
    		if (p == f || p == son[x]) continue;
    		dp[x] = max(dp[x], dep[x] + ln + dep[p]);
    	}
    	dp[x] = max(dp[x], dep[x]);
    	return 0;
    }
    
    
    int main() {
    	scanf("%d", &n);
    	int be, en;
    	ll len;
    	for (int i = 1; i < n; i++) {
    		scanf("%d %d %lld", &be, &en, &len);
    		add(be, en, len);
    		add(en, be, len);
    	}
    	dfs(1, -1, 0);
    	t = s;int r = s;
    	dfs(r, -1, 0);
    	//算好直径了
    	dfs1(s, -1);
    	for (int i = 1; i <= n; i++) {
    		dp1[i] = dp[i];
    		dp[i] = 0;
    		dep[i] = 0;
    	}
    	dfs1(t, -1);
    	//dp1 --- s当根,
    	int x = s;
    	ll ans = 1e17;
    
    	while (x != -1) {
    		int y = fa[x];
    		//x用dp,y用dp1
    		ll cns = max(dp[x], dp1[y]);
    		ans = min(ans, cns);
    		x = y;
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    

      

    寻找真正的热爱
  • 相关阅读:
    C# 印刷文字识别-营业执照
    C# 印刷文字识别-身份证识别
    web视频点播平台
    web书籍信息管理系统
    web数字图书馆系统
    web文件监控系统
    web陶瓷商城管理系统
    web物品交易管理系统
    web校园单车管理平台
    web校园二手物品管理平台
  • 原文地址:https://www.cnblogs.com/lesning/p/12635111.html
Copyright © 2011-2022 走看看