hdu 3394 Railway

http://acm.hdu.edu.cn/showproblem.php?pid=3394

题意:给定一个有N个点,M条边的无向图,求有多少条边没有在环内,有多少条边在至少2个环内。

思路:画一下图,很容易就想到在一个双连通图里,如果边数>点数,则此双连通图里的边都是在2个环内的。其实是错的,下面数据就是这样的特例:
6 6

1 2

1 3

2 3

3 4

3 5

4 5

其中3为割点。主要就是处理这种数据,在tarjan中,u是v的父亲,从v回溯到u,如果low[v]>dfn[u],则说明v到u没有环,如果low[v]==dfn[u],则说明u到v有环;这两种情况都要处理。

View Code
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<cmath>
#include<bitset>
#include<string>
#include<climits>
#include<cstdio>
#include<vector>
#include<utility>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define IN puts("in")
#define OUT puts("out")
#define FR(x) freopen(x,"r",stdin)
#define FW(x) freopen(x,"w",stdout)
#define ST system("pause")

using namespace std;
const int maxn = 10005;
struct nd
{
        int u,v,next;
}edge[maxn*20];
int head[maxn],vis[maxn],dfn[maxn],low[maxn],as[maxn],st[maxn];
int ecnt,cnt,idx,tp,ans1,ans2;
void add(int u,int v)
{
        edge[ecnt].u = u;
        edge[ecnt].v = v;
        edge[ecnt].next = head[u];
        head[u] = ecnt++;
}
void getans()
{
        int i,u,v,j,a=0;
        for(i = 0; i < cnt; ++ i)
        {
                u = as[i];
                for(j = head[u]; j != -1; j = edge[j].next)
                {
                        v = edge[j].v;
                        if(vis[v])a++;
                }
        }
        a /= 2;
        if(a>cnt) ans2 += a;
        if(a<cnt) ans1 += a;
}
void tarjan(int pre,int u)
{
        int i,v,x;
        dfn[u] = low[u] = ++idx;
        st[++tp] = u;
        for(i = head[u]; i != -1; i = edge[i].next)
        {
                v = edge[i].v;
                if(v==pre)continue;
                if(!dfn[v]){
                        tarjan(u,v);
                        low[u] = min(low[v],low[u]);
                        if(low[v]>=dfn[u])
                        {
                                cnt = 0;
                                do{
                                        x = st[tp--];
                                        vis[x] = 1;
                                        as[cnt++] = x;
                                }while(v!=x);
                                as[cnt++] = u;
                                vis[u] = 1;
                                getans();
                                for(x=0;x<cnt;vis[as[x++]]=0);
                        }
                }else low[u] = min(dfn[v],low[u]);
        }
}
int main()
{
        int i,n,m,u,v;
        while(scanf("%d %d",&n,&m)==2)
        {
                if(n+m==0)break;
                memset(dfn,0,sizeof(dfn));
                memset(low,0,sizeof(low));
                memset(head,-1,sizeof(head));
                ecnt = cnt = idx = 0;
                for(i = 0; i < m; ++ i)
                {
                        scanf("%d %d",&u,&v);
                        add(u,v); add(v,u);
                }
                ans1 = ans2 = tp = 0;
                for(i = 0; i < n; ++ i)if(!dfn[i]) tarjan(-1,i);
                printf("%d %d\n",ans1,ans2);
        }
        return 0;
}

posted on 2012-07-03 17:01  aigoruan  阅读(192)  评论(0)    收藏  举报

导航