http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2506

连通分量   缩点后形成新的图(不用新建也可以) 是一个森林

如果缩点后是就剩一个点 则答案为 0

否则 对于缩点后的某一个点   如果和它相连点(缩点后的)有大于等于2个 则无需再连

如果和它相连的有一个点 则需要加一个边连接它 如果没有点和它相连 则需要加两条

统计总共需要加的边的个数sum 因为每条边连接两个点 所以答案为 (sum+1)/2

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<algorithm>
#define LL long long
using namespace std;
const int N=5015;
const int M=10005;
int head[N],I;
struct node
{
    int j,next;
}side[M*2];
int dfn[N],low[N],f[N],deep;
bool visited[N],in[N];
stack<int>st;
set<int>numt[N];
void add(int i,int j)
{
    side[I].j=j;
    side[I].next=head[i];
    head[i]=I++;
}
void dfs(int x,int pre)
{
    dfn[x]=low[x]=deep++;
    st.push(x);
    in[x]=true;
    visited[x]=true;
    for(int t=head[x];t!=-1;t=side[t].next)
    {
        int j=side[t].j;
        if(j==pre)
        continue;
        if(!visited[j])
        {
            dfs(j,x);
            low[x]=min(low[x],low[j]);
        }else if(in[j])
        {
            low[x]=min(low[x],dfn[j]);
        }
    }
    if(low[x]==dfn[x])
    {
        while(st.top()!=x)
        {
            in[st.top()]=false;
            f[st.top()]=x;
            st.pop();
        }
        in[st.top()]=false;
        f[st.top()]=x;
        st.pop();
    }
}
int main()
{
    //freopen("data.in","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
    {
       memset(head,-1,sizeof(head));
       I=0;
       int n,m;
       scanf("%d %d",&n,&m);
       while(m--)
       {
           int l,r;
           scanf("%d %d",&l,&r);
           add(l,r);
           add(r,l);
       }
       while(!st.empty())
       st.pop();
       memset(in,false,sizeof(in));
       memset(visited ,false,sizeof(visited));
       deep=1;
       int treenum=0;
       for(int i=1;i<=n;++i)
       {
           if(!visited[i])
           {
               dfs(i,-1);
               ++treenum;
           }
       }
       for(int i=1;i<=n;++i)
       numt[i].clear();
       for(int i=1;i<=n;++i)
       {
           for(int t=head[i];t!=-1;t=side[t].next)
           {
               int j=side[t].j;
               if(f[i]!=f[j])
               {
                   numt[f[i]].insert(f[j]);
               }
           }
       }
       int leftnum=0;
       int sum=0;
       for(int i=1;i<=n;++i)
       {
           if(f[i]==i)
           {
               if(numt[i].size()==0)
               {sum+=2;leftnum++;}
               if(numt[i].size()==1)
               {sum+=1;leftnum++;}
           }
       }
       if(treenum==1&&leftnum==1)
       {
           printf("0\n");
       }else
       {
           printf("%d\n",(sum+1)/2);
       }
    }
    return 0;
}

  

 

posted on 2012-12-10 11:46  夜->  阅读(226)  评论(1编辑  收藏  举报