Tarjan求割点——HDU 4587

来源:互联网 发布:云计算都招聘什么岗位 编辑:程序博客网 时间:2024/06/06 00:16
  • 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4587

  • 题意:从一个无向图中删除任意两个点,求能得到的连通分量的最大个数

  • 分析:想要增加联通分量的个数,我们肯定想到是去删除割点。但是题中要删除2个点,所以我们第一次删除点时,不应该只奔着割点去,因为有可能删除一些非割点能够创造出新的割点,所以第一次删点应该枚举每一个点,第二次删除点就可以在删除第一个点的前提下,计算出每个割点删除后能增加多少个联通分量。

  • Tarjan计算删除某个割点增加的联通分量

void dfs(int u, int fa){    dfn[u] = low[u] = tmp++;    vis[u] = 1;    sum[u] = 0;//初始化为0,增加的联通分量数为0    for(int i=head[u];i!=-1;i=edge[i].next)    {        int v = edge[i].v;        if(v!=del && v!=fa)        {            if(!vis[v])            {                dfs(v,u);                low[u] = min(low[v], low[u]);                if(low[v] >= dfn[u]) sum[u]++;//如果有一条树边指向的子节点的low[v]>=dfn[u]则该点u一定为割点,且删除它后,可以增加一个联通分量            }            else low[u] = min(low[u],dfn[v]);        }    }    if(u==fa) sum[u]--;//根节点增加的联通分量减1,因为最开始计算了一个整体的联通分量。且若删除根节点没有增加连通分量(可能只有根节点1个点),那么根节点要被删除,即这个子图里没有点了,需要返回-1    if(ans<sum[u]) ans=sum[u];    return;}
  • AC代码:
/*************************************************************************    > File Name: test.cpp    > Author: Akira     > Mail: qaq.febr2.qaq@gmail.com  ************************************************************************/#include <iostream>#include <sstream>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include <algorithm>#include <bitset>#include <queue>#include <stack>#include <map>#include <cmath>#include <vector>#include <set>#include <list>#include <ctime>#include <climits>typedef long long LL;typedef unsigned long long ULL;typedef long double LD;#define MST(a,b) memset(a,b,sizeof(a))#define CLR(a) MST(a,0)#define Sqr(a) ((a)*(a))using namespace std;#define MaxN 5001#define MaxM MaxN*2#define INF 0x3f3f3f3f#define PI 3.1415926535897932384626const int mod = 1E9+7;const double eps = 1e-6;#define bug cout<<88888888<<endl;#define debug(x) cout << #x" = " << x << endl;struct Edge{    int u, v, next;}edge[MaxM];int cont,head[MaxN];int n,m;void add(int u, int v){    edge[cont].u = u;     edge[cont].v = v;     edge[cont].next = head[u];     head[u] = cont++;}int dfn[MaxN],low[MaxN],vis[MaxN];int sum[MaxN],ans,ret,del,tot,tmp;void dfs(int u, int fa){    dfn[u] = low[u] = tmp++;    vis[u] = 1;    sum[u] = 0;    for(int i=head[u];i!=-1;i=edge[i].next)    {        int v = edge[i].v;        if(v!=del && v!=fa)        {            if(!vis[v])            {                dfs(v,u);                low[u] = min(low[v], low[u]);                if(low[v] >= dfn[u]) sum[u]++;            }            else low[u] = min(low[u],dfn[v]);        }    }    if(u==fa) sum[u]--;    if(ans<sum[u]) ans=sum[u];    return;}void solve(){    ans = -1;tot=0;    CLR(vis);    for(int i=1;i<=n;i++)    {        if(!vis[i] && i!=del)        {            tmp = 0;            dfs(i,i);             tot++;        }    }    if(ret < ans + tot)         ret = ans+tot;    return;}void init(){    MST(head,-1);    cont = 0;    CLR(dfn),CLR(low),CLR(sum);    ret = 0;}int main(){    //std::ios::sync_with_stdio(false);    while(~scanf("%d%d", &n, &m))    {        init();        int a,b;        for(int i=0;i<m;i++)        {            scanf("%d%d", &a, &b);            a++,b++;             add(a,b),add(b,a);        }        for(int i=1;i<=n;i++)        {            del = i;             solve();        }        printf("%d\n", ret);    }    //system("pause");}
0 0