• Codeforces 1182D Complete Mirror 树的重心乱搞 / 树的直径 / 拓扑排序


    题意:给你一颗树,问这颗树是否存在一个根,使得对于任意两点,如果它们到根的距离相同,那么它们的度必须相等。

    思路1:树的重心乱搞

    根据样例发现,树的重心可能是答案,所以我们可以先判断一下树的重心可不可以。如果不行,剩下的只可能是度为1点当根了。当然,我们不能枚举所有度为1的点,不然一个菊花图就超时了,我的做法是对于以重心为根的树搜索一遍,对于每个深度的度数为1的点只记录一个,然后枚举这些点,如果有就是有,否则没有。这样最坏的复杂度应该能到O(n * sqrt(n)),但是肯定跑不满。至于为什么这样做,因为感觉每个深度如果有多个点,要么随便选一个都可以,要么都不可以。没想到场上就这样过了,希望评论区有大佬的话能出个hack数据。。。

    代码:

    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f
    #define db double
    #define LL long long
    #define pii pair<int, int>
    using namespace std;
    const int maxn = 100010;
    vector<int> G[maxn];
    void add(int x, int y) {
    	G[x].push_back(y);
    	G[y].push_back(x);
    }
    bool flag = 0;
    bool v[maxn];
    int sz[maxn], n, re[maxn];
    int ans = INF, root;
    map<int, int> mp;
    map<int, int> ::iterator it;
    void dfs(int x) {
    	v[x] = 1;
    	sz[x] = 1;
    	int max_part = 0;
    	for (auto y : G[x]) {
    		if(v[y]) continue;
    		dfs(y);
    		sz[x] += sz[y];
    		max_part = max(max_part, sz[y]);
    	}
    	max_part = max(max_part, n - sz[x]);
    	if(max_part < ans) {
    		ans = max_part;
    		root = x;
    	}
    }
    void dfs1(int x, int fa, int deep) {
    	if(re[deep] == 0) {
    		re[deep] = G[x].size();
    	} else {
    		if(re[deep] != G[x].size()) {
    			flag = 1;
    		//	return;
    		}
    	}
    	sz[x] = 1;
    	for (auto y : G[x]) {
    		if(y == fa) continue;
    		dfs1(y, x, deep + 1);
    		//if(flag == 1) return;
    		sz[x] += sz[y];
    	}
    	if(G[x].size() == 1) {
    		mp[deep] = x;
    	}
    }
    bool solve() {
    	flag = 0;
    	memset(re, 0, sizeof(re));
    	for (auto y : G[root]) {
    		dfs1(y, root, 1);
    	}
    	int now = 0;
    	for (auto y : G[root]) {
    		if(now == 0) now = sz[y];
    		else {
    			if(now != sz[y]) {
    				flag = 1;
    				return flag;
    			}
    		}
    	}
    	return flag;
    }
    int main() {
    	int x, y;
    	scanf("%d", &n);
    	for (int i = 1; i < n; i++) {
    		scanf("%d%d", &x, &y);
    		add(x, y);
    	}
    	dfs(1);
    	if(!solve()) {
    		printf("%d
    ", root);
    		return 0;
    	}
    	else {
    		for (it = mp.begin(); it != mp.end(); it++) {
    			root = it -> second;
    			if(!solve()) {
    				printf("%d
    ", root);
    				return 0;
    			}
    		}
    	}
    	printf("-1
    ");
    } 
    

     思路2:(官方题解)跑一遍树的直径,先判断直径两端行不行,如果不行,从直径的中点开始,找不经过直径上的边可以到达的度数为1的点,判断行不行。

     代码就咕了

       思路3:(官方题解)跑一遍拓扑排序,直到只剩一个点,然后找到这个点最近的和最远的度数为1的点,判断行不行。

       代码也咕了

      思路2和思路3只能直观感受上好像是对的QAQ, 不会证,场上想不出来这种思路,只能乱搞水一水了QAQ 。

      结合官方题解的图应该更好理解思路2和思路3:

      官方题解:https://codeforces.com/blog/entry/67614

  • 相关阅读:
    CodeForces 203C Photographer
    CodeForces 190A Vasya and the Bus
    CodeForces 187A Permutations
    Zoj3762 等待解决
    LA4080最短路树的应用
    uva10917 dij单源最短路预处理+构造新图(DAG)+求图上路径数
    uva11374 dij单源最短路+枚举
    LA3713 2-sat(用到两种矛盾关系)
    【算法总结】2-sat中对象的5种矛盾关系及其连边方式
    LA3211二分答案+2-sat+总结的此类问题统一建模方法
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/11012957.html
Copyright © 2020-2023  润新知