hdu 4612 Warm up 双连通缩点+树的直径

首先双连通缩点建立新图(顺带求原图的总的桥数,其实由于原图是一个强连通图,所以桥就等于缩点后的边)

此时得到的图类似树结构,对于新图求一次直径,也就是最长链。

我们新建的边就一定是连接这条最长链的首尾,这样就将原图的桥减少了直径个。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define maxn 200005
#define maxm 2000005
struct node
{
    int to,vis,next;
}e[maxm],e2[maxm];
int head[maxn],head2[maxn],en,en2;
int belong[maxn],vis[maxn],dfn[maxn],low[maxn],cnt,bridge,col,stack[maxn],top;
bool use[maxn];
void add(int a,int b)
{
    e[en].to=b;
    e[en].vis=0;
    e[en].next=head[a];
    head[a]=en++;
    e[en].to=a;
    e[en].vis=0;
    e[en].next=head[b];
    head[b]=en++;
}
void add2(int a,int b)
{
    e2[en2].to=b;
    e2[en2].next=head2[a];
    head2[a]=en2++;
    e2[en2].to=a;
    e2[en2].next=head2[b];
    head2[b]=en2++;
}
void init()
{
    top=cnt=col=bridge=en2=en=0;
    memset(vis,0,sizeof(vis));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(use,0,sizeof(use));
    memset(head2,-1,sizeof(head2));
    memset(head,-1,sizeof(head));
}
void Tarjan (int u)
{
    int v;
    vis[u] = 1;
    dfn[u] = low[u] = ++cnt;
    stack[top++] = u;
    for (int i = head[u];i != -1;i = e[i].next)
    {
        v = e[i].to;
        if (e[i].vis) continue;
        e[i].vis = e[i^1].vis = 1;
        if (vis[v] == 1)
            low[u] = min(low[u],dfn[v]);
        if (!vis[v])
        {
            Tarjan (v);
            low[u] = min(low[u],low[v]);
            if (low[v] > dfn[u])
                bridge ++;
        }
    }
    if (dfn[u] == low[u])
    {
        ++col;
        do{
            v = stack[--top];
            vis[v] = 0;
            belong[v] = col;
        }while (u != v);
    }
}
int len,st;
void dfs(int now,int sum,int fa)
{
    use[now]=1;
    if(sum>len) {st=now;len=sum;}
    for(int i=head2[now];~i;i=e2[i].next)
    {
        if(!use[e2[i].to]) dfs(e2[i].to,sum+1,now);
    }
}
inline int ReadInt()
{
    char ch = getchar();
    int data = 0;
    while (ch < '0' || ch > '9')
    {
        ch = getchar();
    }
    do
    {
        data = data*10 + ch-'0';
        ch = getchar();
    }while (ch >= '0' && ch <= '9');
        return data;
}
int main()
{
    int n,m,a,b;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(!n&&!m) break;
        init();
        for(int i=1;i<=m;i++)
        {
            a=ReadInt();
            b=ReadInt();
            add(a,b);
        }
        Tarjan(1);
        for(int i=1;i<=n;i++)
            for(int j=head[i];~j;j=e[j].next)
            {
                int to=e[j].to;
                if(belong[to]!=belong[i]) {add2(belong[to],belong[i]);}
            }
        len=0;dfs(1,0,-1);
        memset(use,0,sizeof(use));
        len=0;dfs(st,0,-1);
        printf("%d\n",bridge-len);
    }
    return 0;
}

hdu 4612 Warm up 双连通缩点+树的直径

时间: 2024-10-01 05:02:05

hdu 4612 Warm up 双连通缩点+树的直径的相关文章

hdu4612(双连通缩点+树的直径)

传送门:Warm up 题意:询问如何加一条边,使得剩下的桥的数目最少,输出数目. 分析:tarjan缩点后,重新建图得到一棵树,树上所有边都为桥,那么找出树的直径两个端点连上,必定减少的桥数量最多,因此ans=树的边数-树的直径. #pragma comment(linker,"/STACK:1024000000,1024000000") #include <cstdio> #include <cstring> #include <string>

HDU 5409 CRB and Graph 双连通缩点 + st表

HDU 5409 显然要先双连通缩成一棵树. 然后对于树上的边才有答案. 对于一条边来说, 两侧的最大值分为mx1 , mx2 , 那么 u 一定是min(mx1, mx2), v 一定是 u + 1. 这个经过仔细分析一下就能得到, 然后按dfs序建个st表就好啦. #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi firs

HDU 4005 The war(双连通好题)

HDU 4005 The war 题目链接 题意:给一个连通的无向图,每条边有一个炸掉的代价,现在要建一条边(你不不知道的),然后你要求一个你需要的最少代价,保证不管他建在哪,你都能炸掉使得图不连通 思路:炸肯定要炸桥,所以先双连通缩点,得到一棵树,树边是要炸的,那么找一个最小值的边,从该边的两点出发,走的路径中,把两条包含最小值的路径,的两点连边,形成一个环,这个环就保证了最低代价在里面,除了这个环以外的最小边,就是答案,这样的话,就利用一个dfs,搜到每个子树的时候进行一个维护即可 代码:

Hdu 4612 Warm up (双连通分支+数的直径)

题目链接: Hdu 4612 Warm up 题目描述: 给一个无向连通图,问加上一条边后,桥的数目最少会有几个? 解题思路: 题目描述很清楚,题目也很裸,就是一眼看穿怎么做的,先求出来双连通分量,然后缩点重新建图,用bfs求树的直径,直径的长度就是减去桥的数目. 这个题目需要手动扩展,而且手动扩展的话要用C++提交,G++re哭了. 1 #include <cstdio> 2 #include <queue> 3 #include <cstring> 4 #inclu

HDU 2460 Network(双连通+树链剖分+线段树)

HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链剖分+线段树处理 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #pragma comment(linke

poj3694--Network(双连通缩点+lca)

poj3694:题目链接 题目大意:给出n个点,m条无向边的图,图中存在割边,问每加入一条新的边后的割边的数量 首先,进行双连通缩点,缩点后的图变成一棵树,树上的每条边都是割边,然后没加入一条新的边后,会使这条边的两个点到这两个点的lca形成一个环,使原本的割边减少. 图学的不好,只能显式建树,后来发现建树后没什么用,等以后再修改了 #include <cstdio> #include <cstring> #include <algorithm> #include &l

poj 2942 Knights of the Round Table 【双连通缩点+判奇圈】【经典】

题目:poj 2942 Knights of the Round Table 题意:n个骑士经常一起开会,其中有一些两两相互憎恨,他们不能同一桌,开会要表决一些事情,所以必须奇数个人,最少3个,求永远也参加不了会议的人的个数. 分析:这个题目两点 首先,建图求双连通缩点 建图的话,因为相互憎恨的不能再一块,所以要建补图,让能够在一起的所有的连接,这样的话,如果能存在环且环上的点是奇数个的话就可以参加会议,标记求不能参加的即可. 建好图之后用tarjan算法双连通缩点,把在一个环上的点保存起来.

HDU 4612 Warm up(双连通分量缩点+求树的直径)

思路:强连通分量缩点,建立一颗新的树,然后求树的最长直径,然后加上一条边能够去掉的桥数,就是直径的长度. 树的直径长度的求法:两次bfs可以求,第一次随便找一个点u,然后进行bfs搜到的最后一个点v,一定是直径的一个端点(证明从略),第二次以点v为开头进行bfs,求出的最后一个点,就是直径的另一个端点,记录深度就是我们要求的长度.我这里是使用的bfs+dfs,是一样的,少开一个deep数组,节省一下空间吧…… 其实我一开始是不会求的,我以为随便一个叶子节点就可以做端点,交上去WA,当时还好奇感觉

HDU 4612——Warm up——————【边双连通分量、树的直径】

Warm up Time Limit:5000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4612 Description N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel bet