POJ 2117 (割点+连通分量)

题目链接http://poj.org/problem?id=2117

题目大意:在一个非连通图中,求一个切除图中任意一个割点方案,使得图中连通分量数最大。

解题思路

一个大陷阱,m可以等于0,这时候要特判,结果就是n-1。

同时出题者脑子秀逗了,也不给C的范围。我开了两倍点大小RE了,于是怒开了五倍点大小才A了。

本题不是连通图,需要先计算原始图中的连通分量。方法就是dfs染色。

然后dfs求割点。

之后枚举割点,由于是非连通图,所以连通分量数=原始分量数+block-1。

-1的原因是,每次相当于对其中一个连通分量计算,加上新的block之后,所以要减-1。

 

#include "cstdio"
#include "cstring"
#include "vector"
using namespace std;
#define maxn 10005
struct Edge
{
    int to,next;
}e[maxn*5];
int dfs_clock,pre[maxn],block,head[maxn],tol;
bool cut[maxn],vis[maxn];
void addedge(int u,int v)
{
    e[tol].to=v;
    e[tol].next=head[u];
    head[u]=tol++;
}
int dfs(int u,int fa)
{
    int lowu=pre[u]=++dfs_clock;
    int child=0;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(!pre[v])
        {
            int lowv=dfs(v,u);
            lowu=min(lowu,lowv);
            if(lowv>=pre[u]) cut[u]=true;
        }
        else if(pre[v]<pre[u]&&v!=fa) lowu=min(lowu,pre[v]);
    }
    if(fa<0&&child==1) cut[u]=false;
    return lowu;
}
void check(int u,int fa)
{
    vis[u]=true;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(!vis[v])
        {
            if(u==fa) block++;
            check(v,fa);
        }
    }
}
void link(int u) //判断初始连通分量
{
    vis[u]=true;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].to;
        if(!vis[v]) link(v);
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int n,m,u,v;
    while(scanf("%d%d",&n,&m)&&n)
    {
        memset(head,-1,sizeof(head));
        memset(pre,0,sizeof(pre));
        memset(cut,false,sizeof(cut));
        dfs_clock=0;tol=0;
        if(m==0) printf("%d\n",n-1); //特判
        else
        {
            for(int i=1; i<=m; i++)
            {
                scanf("%d%d",&u,&v);
                addedge(u,v);
                addedge(v,u);
            }
            int res=0,tt=0;
            for(int i=0; i<n; i++) if(!vis[i]) {tt++;link(i);}
            memset(vis,false,sizeof(vis));
            for(int i=0; i<n; i++) if(!pre[i])  dfs(i,-1);
            res=tt;
            for(int i=0; i<n; i++)
            {
                if(cut[i])
                {
                    check(i,i);
                    if(tt) res=max(res,block+tt-1);
                    block=0;
                    memset(vis,false,sizeof(vis));
                }
            }
            printf("%d\n",res);
        }
    }
}

 

posted @ 2014-10-30 11:33  Physcal  阅读(724)  评论(0编辑  收藏  举报