Warm up---hdu4612(求树的直径)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612

给一个无向图, 加上一条边后,求桥至少有几个;

那我们加的那条边的两个顶点u,v;一定是u,v之间含有桥的数量最多,然后uv之间的桥都没了,剩下的就是要求的结果;

树的直径的定义刚好就是两个节点之间含有最多的边;

下面是有关树的直径的知识;

这个题目需要手动扩展,不然会爆栈,而且手动扩展的话要用C++提交。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define N 200005
int Head1[N], Head2[N], cnt[3];
int Stack[N], top, dfn[N], low[N], Time, n, m;
int nBridge, Bridge[N];
int dist[N], vis[N], Max, index;
struct Edge
{
    int v, next;
} e1[10*N], e2[10*N];
void Init()
{
    top = nBridge = Time = Max = index = 0;
    cnt[1] = cnt[0] = 0;
    memset(low, 0, sizeof(low));
    memset(dfn, 0, sizeof(dfn));
    memset(Bridge, 0, sizeof(Bridge));
    memset(dist, 0, sizeof(dist));
    memset(Stack, 0, sizeof(Stack));
    memset(Head1, -1, sizeof(Head1));
    memset(Head2, -1, sizeof(Head2));
}
void Add(Edge e[],int Head[], int u, int v, int k)
{
    e[cnt[k]].v = v;
    e[cnt[k]].next = Head[u];
    Head[u] = cnt[k]++;
}
void Tarjar(int u, int father)
{
    low[u] = dfn[u] = ++Time;
    Stack[top++] = u;
    int v, k=0;
    for(int i=Head1[u]; i!=-1; i=e1[i].next)
    {
        v = e1[i].v;
        if(v==father && !k)///避免重边;
        {
            k++;
            continue;
        }
        if(!dfn[v])
        {
            Tarjar(v, u);
            low[u] = min(low[u], low[v]);
        }
        else
            low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u])
    {
        nBridge++;///可以代表缩点后的节点个数;
        while(1)
        {
            v = Stack[--top];
            Bridge[v] = nBridge;///缩点;
            if(u==v)
                break;
        }
    }
}
void bfs(int s)
{
    queue<int>Q;
    int p, q;
    memset(vis, 0, sizeof(vis));
    vis[s] = 1;
    dist[s] = 0;
    Q.push(s);
    while(!Q.empty())
    {
        p = Q.front(); Q.pop();
        for(int i=Head2[p]; i!=-1; i=e2[i].next)
        {
            q = e2[i].v;
            if(!vis[q])
            {
                vis[q] = 1;
                dist[q] = dist[p] + 1;
                Q.push(q);
                if(Max<dist[q])
                {
                    Max = dist[q];
                    index = q;
                }
            }
        }
    }
}
int main()
{
    int u, v;
    while(scanf("%d%d", &n, &m), m + n)///输入时由于m n弄反了,TLE的我想哭;
    {
        Init();
        for(int i=1; i<=m; i++)
        {
            scanf("%d%d", &u, &v);
            Add(e1, Head1, u, v, 0);
            Add(e1, Head1, v, u, 0);///原来的树;
        }
        Tarjar(1, 0);
        for(int i=1; i<=n; i++)
        {
            for(int j=Head1[i]; j!=-1; j=e1[j].next)
            {
                int u = Bridge[i];
                int v = Bridge[e1[j].v];
                if(u != v )
                {
                    Add(e2, Head2, u, v, 1);
                    Add(e2, Head2, v, u, 1);///缩点后的树;
                }
            }
        }
        bfs(1);
        bfs(index);///求树的直径的过程;
        printf("%d\n", nBridge-1-Max);///缩点后形成的树每条边都是桥;所以总桥的个数为节点数-1;
    }
    return 0;
}

时间: 2024-11-05 13:45:52

Warm up---hdu4612(求树的直径)的相关文章

hdu4612 无向图中任意添加一条边后使桥的数量最少 / 无向图缩点+求树的直径

题意如上,含有重边(重边的话,俩个点就可以构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选任意起点U,进行bfs,到达最远的一个点v(level最深)该点必然是树的直径的一个端点,,再从该点出发,bfs,到最深的一点,该点深度就是直径.(证明:先假设u,是直径上一点,S,T是直径的端点,设v!=t,则有(V,U)+(U,S)>(T,U)+(U,S),矛盾,故t=v:若u不是直径上一点,设u到直径上的一点为x,同理易证. 最后 缩

hdu4612 连通性,求树的直径,加一边求最少桥

http://acm.hdu.edu.cn/showproblem.php?pid=4612 Problem Description N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel between any two planets through these channels. If we can isolate

hdoj 4612 Warm up【双连通分量求桥&amp;&amp;缩点建新图求树的直径】

Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 5093    Accepted Submission(s): 1131 Problem Description N planets are connected by M bidirectional channels that allow instant transport

(求树的直径)Warm up -- HDU -- 4612

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612 给一个无向图, 加上一条边后,求桥至少有几个: 那我们加的那条边的两个顶点u,v:一定是u,v之间含有桥的数量最多,然后uv之间的桥都没了,剩下的就是要求的结果: 树的直径的定义刚好就是两个节点之间含有最多的边: 下面是有关树的直径的知识: 这个题目需要手动扩展,不然会爆栈,而且手动扩展的话要用C++提交. 代码: #pragma comment(linker, "/STACK:1024000

HDU 4612 Warm up(边双联通求树的直径)

Problem Description N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel between any two planets through these channels. If we can isolate some planets from others by breaking only one

poj2631 求树的直径裸题

题目链接:http://poj.org/problem?id=2631 题意:给出一棵树的两边结点以及权重,就这条路上的最长路. 思路:求实求树的直径. 这里给出树的直径的证明: 主要是利用了反证法: 假设 s-t这条路径为树的直径,或者称为树上的最长路 现有结论,从任意一点u出发搜到的最远的点一定是s.t中的一点,然后在从这个最远点开始搜,就可以搜到另一个最长路的端点,即用两遍广搜就可以找出树的最长路 证明: 1.设u为s-t路径上的一点,结论显然成立,否则设搜到的最远点为T则   dis(u

poj:1985:Cow Marathon(求树的直径)

Cow Marathon Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 5496   Accepted: 2685 Case Time Limit: 1000MS Description After hearing about the epidemic of obesity in the USA, Farmer John wants his cows to get more exercise, so he has com

hdu 4514 湫湫系列故事――设计风景线(求树的直径)

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

lightoj-1094 Farthest Nodes in a Tree(求树的直径)

1094 - Farthest Nodes in a Tree PDF (English) Statistics ForumTime Limit: 2 second(s) Memory Limit: 32 MBGiven a tree (a connected graph with no cycles), you have to find the farthest nodes in the tree. The edges of the tree are weighted and undirect