poj3177 Redundant Paths 边双连通分量

来源:互联网 发布:有寓意的网名知乎 编辑:程序博客网 时间:2024/05/17 04:44

给一个无向图,问至少添加多少条边可以使图变成双连通图(任意两点之间至少有两条不同的路(边不同))。

图中的双连通分量不用管,所以缩点之后建新的无向无环图。

这样,题目问题等效于,把新图中度数为1的点相互连到图里面形成环

假设这样的点有sum个,那么至少需要添加(sum+1)/2 条边。

以下,基本上就是求边双连通分量模板。


#include <iostream>#include <cstring>#include <string>#include <cstdio>#include <cmath>#include <algorithm>#include <vector>#include <queue>#include <map>#define inf 0x3f3f3f3f#define eps 1e-6#define ll __int64using namespace std;#define N 5010#define M 10010struct node{    int v,next,vis;},e[M];int h,head[N];int belong[N],vis[N],dfn[N],low[N],brig[N][2],nbrig,col,cnt,top,in[N],sta[N];int n,m;void addedge(int a,int b){    e[h].v=b;    e[h].vis=0;    e[h].next=head[a];    head[a]=h++;}void tarjan(int u){    int v;    vis[u]=1;    dfn[u]=low[u]=++cnt;    sta[top++]=u;    for(int i=head[u];i!=-1;i=e[i].next)    {        if(e[i].vis) continue;        e[i].vis=e[i^1].vis=1;        v=e[i].v;        if(vis[v]==1)            low[u]=min(low[u],dfn[v]);        if(!vis[v])        {            tarjan(v);            low[u]=min(low[u],low[v]);            if(low[v]>dfn[u])            {                brig[nbrig][0]=u;                brig[nbrig++][1]=v;            }        }    }    if(low[u]==dfn[u])    {        ++col;        do        {            v=sta[--top];            vis[v]=0;            belong[v]=col;        }while(u!=v);    }}void init(){    memset(head,-1,sizeof head);    memset(vis,0,sizeof vis);    memset(belong,-1,sizeof belong);    h=h1=cnt=col=nbrig=top=0;}int main(){    int i,j,k,a,b;    while(~scanf("%d%d",&n,&m))    {        init();        for(i=0;i<m;i++)        {            scanf("%d%d",&a,&b);            addedge(a,b);            addedge(b,a);        }        tarjan(1);        memset(in,0,sizeof in);//记度数//无向图        for(i=0;i<nbrig;i++)//缩点后 树的边是原图里的桥组成        {            a=brig[i][0];            b=brig[i][1];            if(belong[a]!=belong[b])                in[belong[a]]++,in[belong[b]]++;        }        int sum=0;        for(i=1;i<=col;i++)            if(in[i]==1) sum++;        printf("%d\n",(sum+1)/2);    }    return 0;}


下面这个模板太龊。。

#include <iostream>#include <cstring>#include <string>#include <cstdio>#include <cmath>#include <algorithm>#include <vector>#include <queue>#include <map>#define inf 0x3f3f3f3f#define eps 1e-6#define ll __int64using namespace std;#define N 1010#define M 20010struct node{    int v;//下个顶点    node *next;//下个边结点};int n,m,r[N],d[N];//d表示缩点后各顶点的度数node mem[M];int memp;//存储边结点node *e[N];int necc;//原图中边双连通分量的个数int belong[N];int low[N],dfn[N];int vis[N];int brig[M][2],nbrig;void addedge(int i,int j){    node *p=&mem[memp++];    p->v=j;    p->next=e[i];    e[i]=p;}int root(int a){    if(a!=r[a])        r[a]=root(r[a]);    return r[a];}void merge(int a,int b){    int ra=root(a);    int rb=root(b);    if(ra!=rb)        r[ra]=rb;}void dfs(int i,int father,int dth){    int j,tofa=0;    node *p;    vis[i]=1;    low[i]=dfn[i]=dth;    for(p=e[i];p!=NULL;p=p->next)    {        j=p->v;        if(vis[j]&&(j!=father||tofa))            low[i]=min(low[i],dfn[j]);        if(!vis[j])        {            dfs(j,i,dth+1);            low[i]=min(low[i],low[j]);            if(low[j]<=dfn[i]) merge(i,j);//i,j在同一个双联通分量            if(low[j]>dfn[i]) //边i,j是桥            {                brig[nbrig][0]=i;                brig[nbrig++][1]=j;            }        }        if(j==father) tofa=1;    }    vis[i]=2;}int doubleconne(){    int i,k,ncon=nbrig=0;    dfs(0,-1,1);    for(i=0;i<n;i++)    {        k=root(i);        if(belong[k]==-1) belong[k]=ncon++;        belong[i]=belong[k];    }    return ncon;}void init(){    memp=nbrig=0;    memset(e,0,sizeof e);    memset(d,0,sizeof d);    for(int i=0;i<=n;i++)        r[i]=i;    memset(vis,0,sizeof vis);    memset(belong,-1,sizeof belong);}int main(){    int i,j,k,a,b;    while(~scanf("%d%d",&n,&m))    {        init();        for(i=0;i<m;i++)        {            scanf("%d%d",&a,&b);            addedge(a-1,b-1);            addedge(b-1,a-1);        }        necc=doubleconne();        for(k=0;k<nbrig;k++)        {            i=brig[k][0];            j=brig[k][1];            d[belong[i]]++;            d[belong[j]]++;        }        int cnt=0;//收缩后叶子结点的个数        for(i=0;i<necc;i++)            if(d[i]==1) cnt++;        printf("%d\n",(cnt+1)/2);    }    return 0;}


0 0
原创粉丝点击