zoukankan      html  css  js  c++  java
  • JZOJ 5944

    题目大意

    给你一棵树,可以每个点都安放定位器,
    要求你放尽量少的定位器
    使得任意两点(u, v)都至少有一个点 x ,使得 dst[x, u] != dst[x, v]


     简单的手玩后发现,一棵以 x 为根的子树,x 有 k 个儿子

    那么在 x 的子树中 至少要保证有 k - 1 个儿子的子树中有定位器

    否则一定会冲突的,由于他们到 lca 距离是一定的,
    那么 lca 外的子树中同深度的点就无法区分了

    发现有的树会出锅,是一个定位器的祖先两端的点出问题了,
    他们到定位器距离是一样的,深度是不同的,那就先强制往根放一个

    这样深度不同的点就区分开了

    这样 n^2 的做有 70pts

    我也只会 70pts

    考虑什么做法能降复杂度,并不会

    要么推出来下面的性质要么找规律

    可以做到 O(n) ,只要找到一个度数大于 2 的点为根,根不放,进行上边的贪心即可

    考虑证明它

    假设现在一棵根度数为奇数的子树中,有两点无法区分

    根据深度分类讨论一下

    先考虑两点深度相同的时候
    由于任意一点 k 个儿子中 k - 1 个的子树都放有定位器,所以是不存在这种情况的

    接下来是深度不同的情况,还要分三种情况考虑

    一种是两个点在同一棵子树中
    显然还至少会有一个定位器在别的子树中,将他们区分开来

    一种是一个点所在的子树中没有定位器而另一个有
    同上,至少会有一个定位器在别的子树中将他们区分开来

    另一种是两个点所在的子树中都有定位器
    如果根的度数 > 3,同上,至少会有一个定位器在别的子树中将他们区分开来
    如果度数 = 3,那他们肯定是走到了 奇链中点 处,而且这个点是唯一的
    所以一定还有另一个定位器,且它到两点的距离不同

    所以找一个度数大于 2 的点为根 O(n) 贪心的做就好了

    找不到就是链, puts(“1”);


     代码:

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cctype>
    #include <cstdio>
    using namespace std;
    
    const int MAX_N = 1000005;
    
    struct EDGE{
    	int nxt, to;
    	explicit EDGE(int NXT = 0, int TO = 0) {nxt = NXT; to = TO;}
    }edge[MAX_N << 1];
    int n, tot_edge, ans, bgn;
    int head[MAX_N], deg[MAX_N];
    
    inline int rd() {
    	register int x = 0, c = getchar();
    	while (!isdigit(c)) c = getchar();
    	while (isdigit(c)) {
    		x = x * 10 + (c ^ 48);
    		c = getchar();
    	}
    	return x;
    }
    inline void add(int x, int y) {
    	edge[++tot_edge] = EDGE(head[x], y);
    	head[x] = tot_edge;
    	++deg[x];
    	edge[++tot_edge] = EDGE(head[y], x);
    	head[y] = tot_edge;
    	++deg[y];
    	return;
    }
    bool dfs(int x, int frm) {
    	int tot = 0;
    	for (int i = head[x]; i; i = edge[i].nxt) if (edge[i].to != frm) {
    		int y = edge[i].to;
    		tot += dfs(y, x);
    	}
    	if (frm == 0) {
    		if (tot < deg[x] - 1) {
    			ans += (deg[x] - 1 - tot);
    			tot += (deg[x] - 1 - tot);
    		}
    	} else if (tot < deg[x] - 2) {
    		ans += (deg[x] - 2 - tot);
    		tot += (deg[x] - 2 - tot);
    	}
    	return (tot != 0);
    }
    
    int main() {
    	freopen("beacon.in", "r", stdin);
    	freopen("beacon.out", "w", stdout);
    	n = rd();
    	register int xx, yy;
    	for (int i = 1; i < n; ++i) {
    		xx = rd(); yy = rd();
    		add(xx, yy);
    	}
    	if (n == 1) {
    		puts("0");
    		return 0;
    	}
    	for (int i = 1; i <= n; ++i) {
    		if (deg[i] > 2) {
    			bgn = i;
    			break;
    		}
    	}
    	if (!bgn) {
    		puts("1");
    		return 0;
    	}
    	dfs(bgn, 0);
    	printf("%d
    ", ans);
    	return 0;
    }
  • 相关阅读:
    HDU 5115 Dire Wolf (区间DP)
    HDU 4283 You Are the One(区间DP(最优出栈顺序))
    ZOJ 3469 Food Delivery(区间DP好题)
    LightOJ 1422 Halloween Costumes(区间DP)
    POJ 1651 Multiplication Puzzle(区间DP)
    NYOJ 石子合并(一)(区间DP)
    POJ 2955 Brackets(括号匹配一)
    POJ 1141 Brackets Sequence(括号匹配二)
    ZOJ 3537 Cake(凸包+区间DP)
    Graham求凸包模板
  • 原文地址:https://www.cnblogs.com/xcysblog/p/9894075.html
Copyright © 2011-2022 走看看