zoukankan      html  css  js  c++  java
  • ZOJ 3820 Building Fire Stations

    题意:

    树上找两个点  使得其它点到这两点随意一点的距离的最大值最小

    思路:

    最大值最小  想到二分  在二分的基础上判定这个最大值是否可能

    怎样判定这个问题就是怎样选那两个点的问题  非常明显  我们要处理的是直径(不然没意义  最长的就是直径)  那么既然已经有了一个要判定的值x  最好还是就选择距离直径两端点距离为x的点就好

    直径上的点最多n个  算上二分的复杂度  O(nlogn)能够解决

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<vector>
    #include<queue>
    #include<cstdlib>
    #include<ctime>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    #define N 200010
    
    int t, n;
    struct edge {
    	int v, next;
    } ed[N * 2];
    int head[N], tot;
    int dis[N], pre[N];
    int route[N], m;
    
    void add(int u, int v) {
    	ed[tot].v = v;
    	ed[tot].next = head[u];
    	head[u] = tot++;
    }
    
    int qu[N];
    int bfs(int u) {
    	int l = 0, r = 1;
    	int pos = u, val = 0;
    	dis[u] = 0;
    	qu[0] = u;
    	while (l < r) {
    		u = qu[l++];
    		for (int i = head[u]; ~i; i = ed[i].next) {
    			int v = ed[i].v;
    			if (dis[v] == -1) {
    				pre[v] = u;
    				dis[v] = dis[u] + 1;
    				qu[r++] = v;
    				if (dis[v] > val) {
    					val = dis[v];
    					pos = v;
    				}
    			}
    		}
    	}
    	return pos;
    }
    
    int flag[N];
    bool yes(int ans) {
    	memset(flag, 0, sizeof(flag));
    	memset(dis, -1, sizeof(dis));
    	bfs(route[ans]);
    	for (int i = 1; i <= n; i++) {
    		if (dis[i] <= ans)
    			flag[i] = 1;
    	}
    	memset(dis, -1, sizeof(dis));
    	bfs(route[m - 1 - ans]);
    	for (int i = 1; i <= n; i++) {
    		if (dis[i] <= ans)
    			flag[i] = 1;
    	}
    	for (int i = 1; i <= n; i++) {
    		if (!flag[i])
    			return false;
    	}
    	return true;
    }
    
    int main() {
    	int i, u, v;
    	scanf("%d", &t);
    	while (t--) {
    		tot = 0;
    		memset(head, -1, sizeof(head));
    		scanf("%d", &n);
    		for (i = 1; i < n; i++) {
    			scanf("%d%d", &u, &v);
    			add(u, v);
    			add(v, u);
    		}
    		memset(dis, -1, sizeof(dis));
    		u = bfs(1);
    		memset(dis, -1, sizeof(dis));
    		memset(pre, -1, sizeof(pre));
    		v = bfs(u);
    		m = 0;
    		while (v != -1) {
    			route[m++] = v;
    			v = pre[v];
    		}
    		int l = 0, r = m - 1, mid, ans[3];
    		while (l <= r) {
    			mid = (l + r) / 2;
    			if (yes(mid)) {
    				ans[0] = mid;
    				ans[1] = route[mid];
    				ans[2] = route[m - 1 - mid];
    				if (ans[1] == ans[2]) {
    					for (i = 0; i < m; i++) {
    						if (route[i] != ans[1]) {
    							ans[2] = route[i];
    							break;
    						}
    					}
    				}
    				r = mid - 1;
    			} else
    				l = mid + 1;
    		}
    		printf("%d %d %d
    ", ans[0], ans[1], ans[2]);
    	}
    	return 0;
    }
    


  • 相关阅读:
    在Win7 64位电脑上安装Sql Server 2008 R2 Express
    尝试u盘重装系统
    摘自《北方人》
    编写一个换算GPA 的Application 程序,对于学生学习的每门课程,都输入两个整数:考试成绩和学分,考试成绩按如下公式换算: 85~100:4 75~84:3 60~74:2 45~59:1 44以下:0 GPA等于换算后每门课的成绩的学分加权平均值
    java编程题
    生成器并发处理其实就是函数的切换
    生成器与文档结合
    生成器函数
    生成器表达式、三元表达式、列表解析
    迭代,列表,字典,文件迭代
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/4471222.html
Copyright © 2011-2022 走看看