HDU Problem 4514 湫湫系列故事——设计风景线 【并查集+树的直径】

湫湫系列故事——设计风景线

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 4115    Accepted Submission(s): 725

Problem Description
  随着杭州西湖的知名度的进一步提升,园林规划专家湫湫希望设计出一条新的经典观光线路,根据老板马小腾的指示,新的风景线最好能建成环形,如果没有条件建成环形,那就建的越长越好。
  现在已经勘探确定了n个位置可以用来建设,在它们之间也勘探确定了m条可以设计的路线以及他们的长度。请问是否能够建成环形的风景线?如果不能,风景线最长能够达到多少?
  其中,可以兴建的路线均是双向的,他们之间的长度均大于0。
 
Input
  测试数据有多组,每组测试数据的第一行有两个数字n, m,其含义参见题目描述;
  接下去m行,每行3个数字u v w,分别代表这条线路的起点,终点和长度。

  [Technical Specification]
  1. n<=100000 
  2. m <= 1000000
  3. 1<= u, v <= n 
  4. w <= 1000
 
Output
  对于每组测试数据,如果能够建成环形(并不需要连接上去全部的风景点),那么输出YES,否则输出最长的长度,每组数据输出一行。
 
Sample Input
3 3 1 2 1 2 3 1 3 1 1
 
Sample Output
YES
 
Source
 
Recommend
liuyiding   |   We have carefully selected several similar problems for you:  5792 5791 5790 5789 5788 
 
一开始无限次超时(其实已经预感到了),看了前辈的博客之后才知道每棵树只要判断一次就好,这样可降低时间的复杂度。

#include <bits/stdc++.h>
#define MAXN 100010
using namespace std;
struct node{
    int from, to, val, next;
} edge[MAXN*2];
bool vis[MAXN], flag, used[MAXN];
int dist[MAXN], head[MAXN], edgenum, ans, s, n, m;
void addEdge(int x, int y, int z) {
    edge[edgenum].from = x;
    edge[edgenum].to = y;
    edge[edgenum].val = z;
    edge[edgenum].next = head[x];
    head[x] = edgenum++;
}
void bfs(int x) {
    queue<int> que; ans = 0;
    memset(vis, false, sizeof(vis));
    memset(dist, 0, sizeof(dist));
    while (!que.empty()) que.pop();
    que.push(x); vis[x] = true;
    while (que.size()) {
        int a = que.front(); que.pop();
        //标记是否已经访问过这棵树
        used[a] = true;
        for (int i = head[a]; i != -1; i = edge[i].next) {
            int b = edge[i].to;
            if (!vis[b] && dist[b] < dist[a] + edge[i].val) {
                dist[b] = dist[a] + edge[i].val;
                if(ans < dist[b]) {
                    ans = dist[b]; s = b;
                }
                vis[b] = true; que.push(b);
            }
        }
    }
}
int par[MAXN];
int Find(int x) {
    if (x == par[x]) return x;
    return par[x] = Find(par[x]);
}
void unite(int x, int y) {
    int fx = Find(x);
    int fy = Find(y);
    if (fx != fy) par[fy] = fx;
    else flag = true;
}
void init() {
    for (int i = 0; i <= n; i++) {
        par[i]= i;
    }
    memset(head, -1, sizeof(head));
    edgenum = 0;
}
int main() {
    int a, b, c, d;
    while (scanf("%d%d", &n, &m) != EOF) {
        init(); flag = false;
        memset(used, false, sizeof(used));
        for (int i = 0; i < m; i++) {
            scanf("%d%d%d", &a, &b, &c);
            if (flag) continue;
            unite(a, b); addEdge(a, b, c);
            addEdge(b, a, c); d = a;
        }
        int maxx = 0;
        if (flag) printf("YES
");
        else {
            for (int i = 1; i <= n; i++) {
                //如果节点所在的树没被访问过
                if (!used[i]&& par[i] == i) {
                    bfs(i), bfs(s);
                    maxx = max(maxx, ans);
                }
            }
            printf("%d
", maxx);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/cniwoq/p/6770870.html