标签:zoj acm bfs 2014牡丹间 2014区域赛
给一棵最多2*10^5个结点的树,选择两个结点放置设备,要求所有结点其到最近设备的最远距离最小,求出这个最小距离。
最大值最小,首先想到二分。二分一个最大距离M,先以1号结点bfs出每个结点的深度。任选一个最大深度的结点,则离他距离M的父结点u上必须要放置一个设备。然后再以u进行bfs,同样的选择出第二个结点。再把选择的两个设备结点加入队列bfs,看是否能够遍历所有点,若能就满足。
zju上面做的,dfs会栈溢出。第一次以一号结点bfs可以预处理,之后直接取出最大深度的点就行。有可能两次找的放置设备的点相同,注意特判一下。二分过程完成后,有可能最后一次判断不成立,此时得到的两个设备的点不是题目所求,需要再判断一次。具体见代码。
//#include <bits/stdc++.h> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> #include <string> #include <set> #include <stack> #include <map> #include <cmath> #include <vector> #include <iostream> #include <algorithm> using namespace std; //LOOP #define FF(i, a, b) for(int i = (a); i < (b); ++i) #define FE(i, a, b) for(int i = (a); i <= (b); ++i) #define REP(i, N) for(int i = 0; i < (N); ++i) #define CLR(A,value) memset(A,value,sizeof(A)) //OTHER #define PB push_back #define RI(n) scanf("%d", &n) #define RII(n, m) scanf("%d%d", &n, &m) #define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k) typedef long long LL; typedef unsigned long long ULL; typedef vector <int> VI; const int INF = 0x3f3f3f3f; const double EPS = 1e-9; const int MOD = 1000000007; const double PI = acos(-1.0); const int maxn = 200010; int n, M, rt1, rt2, mdrt; VI G[maxn]; int num[maxn], fa[maxn], pre[maxn]; //指定深度任选的一个点,第一次bfs的父亲结点,第二次bfs父亲结点 bool vis[maxn]; void init() { REP(i, n + 1) G[i].clear(); } struct Node{ int id, d; Node() {} Node(int a, int b) : id(a), d(b) {} }t; int bfs(int s, int ff[]) { CLR(vis, 0); queue<Node> Q; Q.push(Node(s, 0)); vis[s] = 1, ff[s] = 0; int md = 0; while (!Q.empty()) { t = Q.front(); Q.pop(); int u = t.id; num[t.d] = u; md = max(md, t.d); REP(i, G[u].size()) { int v = G[u][i]; if (!vis[v]) { vis[v] = 1; ff[v] = u; Q.push(Node(v, t.d + 1)); } } } return md; } int fun() //标记两个设备能到达的点 { CLR(vis, 0); int cnt = 0; queue<Node> Q; vis[rt1] = vis[rt2] = 1; Q.push(Node(rt1, 0)), Q.push(Node(rt2, 0)); while (!Q.empty()) { t = Q.front(); Q.pop(); if (t.d >= M) continue; int u = t.id; REP(i, G[u].size()) { int v = G[u][i]; if (!vis[v]) { vis[v] = 1; Q.push(Node(v, t.d + 1)); } } } FE(i, 1, n) if (vis[i]) cnt++; return cnt; } bool ok() { rt1 = mdrt; REP(i, M) rt1 = pre[rt1]; int md = bfs(rt1, fa); rt2 = num[md]; REP(i, M) rt2 = fa[rt2]; int cnt = fun(); if (cnt >= n) { if (rt1 == rt2) //特判两个点相等时 { if (rt1 + 1 <= n) rt2 = rt1 + 1; else rt2 = rt1 - 1; } return 1; } return 0; } int main() { int T, x, y; RI(T); while (T--) { RI(n); init(); REP(i, n - 1) { RII(x, y); G[x].PB(y), G[y].PB(x); } int md = bfs(1, pre); mdrt = num[md]; int L = 0, R = md; while (L <= R) { M = (L + R) >> 1; if (ok()) R = M - 1; else L = M + 1; } M = L; ok(); //求得最小距离后再判断一次得出放置设备点 printf("%d %d %d\n", L, rt1, rt2); } return 0; } /* 8 8 1 2 1 3 2 4 2 5 3 6 5 7 5 8 ans: 2 1 2 */
2014牡丹江 区域赛 Building Fire Stations
标签:zoj acm bfs 2014牡丹间 2014区域赛
原文地址:http://blog.csdn.net/colin_27/article/details/40043775