hdu 3394 (无向图求块 判断环)

来源:互联网 发布:图章设计软件 编辑:程序博客网 时间:2024/06/03 23:00
                 
题意描述        公园有n个景点,公园的管理员计划要建m条道路,并且安排一些形成回路的参观路径,如果一条道路可以被多条回路共用,        那么这条边是冲突边,如果一个块中有多个环,则该块中的每条边都是冲突边。
        如果不能形成环的路则为不需要的边,现在就是求无向图中冲突边和不需要边的条数
解题思路:
        把图分为多个块,然后判断每个块里面的边数,如果块的边数等于块的点数,那么该块只有一个环,如果块的边数大于块的       点数,那么这个块中有多个环,并且这个块中的每条边都是多个环里面的一部分。

注意:  将块出栈时,只能出到u的子节点v为止 ,因为u作为割点极有可能是该个块与别的块公用的,所以若是每次出栈到u,则会破坏其他的块。(这就是与有向图的tarjan的一个不同之处。)
代码:
#include<iostream>#include<string.h>#include<vector>#define max 10010using namespace std;vector <int> vec[max];int in[max], stack[max] , block[max];int low[max], dfn[max];int top , ans1, ans2 ,step;int n, m;void init(){    for(int i=0;i<max;i++)      {        low[i]=dfn[i]=stack[i]=0;        vec[i].clear();    }    top=-1 ; step=ans1=ans2=0;}void insert(int u, int v){    vec[u].push_back(v);    vec[v].push_back(u);}void deal_circle(){//cout<<block[0]<<endl<<endl;    int num=0;     for(int i=1;i<=block[0];i++)    {//cout<<block[i]<<endl;        for(int j=0;j<vec[block[i]].size();j++)        {            int v=vec[block[i]][j];              if(in[v]) { num++; } //如果v属于当前块,则将边数累加一次         }    }    num/=2;//因为每条边的顶点有两个,且都属于该块中,所以每条边被重复计算了一次     if(block[0]>num)  ans1+=num;    else if(block[0]<num) ans2+=num;    //cout<<"ans1= "<<ans1<<"   ans2= "<<ans2<<endl;}void tarjan(int u ){     int v;     dfn[u]=low[u]=++step;     stack[++top]=u;     for(int i=0;i<vec[u].size(); i++)     {         v=vec[u][i];          if(!dfn[v])   //若该点没有被访问过          {             tarjan(v);             low[u]=min(low[u], low[v]);             if(low[v]>=dfn[u]) //说明u的子节点没有与u的祖先相连的后向边,即u为割项              {                 block[0]=0;    //cout<<endl<<endl;                 memset(in,0,sizeof(in));                 int t;                 do                 {                    t=stack[top--];                    block[++block[0]]=t;                    in[t]=1;  //cout<<u<<"-----"<<t<<endl;                 }while(v!=t);                 block[++block[0]]=u; in[u]=1;                 deal_circle();             }         }         else         low[u]=min(dfn[v] , low[u]);     }}int main(){    int a, b;    while(~scanf("%d%d",&n,&m) && n+m )    {        init();        for(int i=0;i<m;i++)        {           scanf("%d%d",&a,&b);           insert(a,b);        }        for(int i=0;i<n;i++)        if(!dfn[i])  tarjan(i);        printf("%d %d\n",ans1,ans2);    }    return 0;}


原创粉丝点击