hdu 3721

来源:互联网 发布:四十不惑 五十而知天命 编辑:程序博客网 时间:2024/05/13 16:55

借鉴了网上一个大牛的代码


#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAXN = 2500 + 123;struct EDGE{    int v, val, next;    bool flag;}edge[MAXN * 2];int cnt = 0;int head[MAXN];int dis[MAXN];int pre[MAXN];bool vis[MAXN];int q[MAXN];void addedge(int x, int y, int z){    edge[cnt].v = y;    edge[cnt].val = z;    edge[cnt].flag = true;    edge[cnt].next = head[x];    head[x] = cnt++;}int dfs(int src, int& rmin){    memset(dis, -1, sizeof(dis));    int front = 0;    int rear = 0;    q[rear++] = src;    dis[src] = 0;    int id = src;    while(front < rear)//找出直径的一端    {        int now = q[front++];        for(int p = head[now]; p != -1; p = edge[p].next)        {            if(!edge[p].flag)  continue;//删除的边            int v = edge[p].v;            if(dis[v] != -1)  continue;            dis[v] = dis[now] + edge[p].val;            q[rear++] = v;            if(dis[v] > dis[id])            {                id = v;            }        }    }    front = rear = 0;    src = id;    q[rear++] = src;    dis[src] = 0;    id = src;    vis[src] = true;    while(front < rear)    {        int now = q[front++];        for(int p = head[now]; p != -1; p = edge[p].next)        {            if(!edge[p].flag)  continue;//删除的边            int v = edge[p].v;            if(vis[v])  continue;            dis[v] = dis[now] + edge[p].val;            pre[v] = now;            q[rear++] = v;            vis[v] = true;            if(dis[v] > dis[id])            {                id = v;            }        }    }    int half = dis[id] / 2;    int small = dis[id];    rmin = 0;    for(int i = id; i != src; i = pre[i])//找到那个根节点    {        if(dis[i] >= half && dis[pre[i]] <= half)        {            rmin=min(dis[i],small-dis[pre[i]]);            break;        }    }    return small;}int main(){    int T;    int n;    int x, y, z;    scanf("%d", &T);    for(int cas = 1; cas <= T; cas++)    {        scanf("%d", &n);        if(n == 1)        {            printf("Case %d: 0\n",cas);            continue;        }        cnt = 0;        memset(head, -1, sizeof(head));        for(int i = 1; i < n; i++)        {            scanf("%d%d%d", &x, &y, &z);            addedge(x, y, z);            addedge(y, x, z);        }        //开始枚举删边        int a, b, c, d;        int ans = 1 << 30;        for(int i = 0; i < cnt; i+=2)  //注意加2不是加1        {            edge[i].flag = false;            edge[i ^ 1].flag = false;            memset(vis, 0, sizeof(vis));            for(int j = 0; j < n; j++)            if(!vis[j])            {                a = dfs(j, c);//a是这个部分的直径,c是这个部分选定的使最长路最短的根节点发出的最长路                break;            }            for(int j = 0; j < n; j++)            if(!vis[j])            {                b = dfs(j, d);                break;            }            int rmax = max(a, b);            rmax = max(rmax, c + d + edge[i].val);            if(rmax < ans)  ans = rmax;            edge[i].flag = true;            edge[i ^ 1].flag = true;        }        printf("Case %d: %d\n", cas, ans);    }    return 0;}