[点双连通分量]hdoj 3394:Railway
大致题意:
? ? 给出一个无向图,求出割边的条数,并求出存在在多个环中的边的条数。
?
大致思路:
? ? 先给出题人跪了,真的没想明白为什么circuit是点双连通分量的意思,用边双连通分量wa了一上午。知道了是点双连通分量,问题就简单了,如果一个circuit中的点数小于边数,那么这个分量中所有的边肯定是多余的。
?
#include<iostream>#include<cstdio>#include <algorithm>#include<cstring>using namespace std;const int inf=1<<30;const int nMax=30015;const int mMax=500000;class edge{public: int u,v,nex;};edge e[mMax];int k,k1,head[nMax];int dfn[nMax],low[nMax],sta[nMax],top,atype,belon[nMax],dep; bool insta[nMax];int n,m;int ans,vis[nMax],num[nMax],cnt,sum;void addedge(int a,int b){ e[k].u=a; e[k].v=b; e[k].nex=head[a]; head[a]=k;k++;}void getcont(){ int i,j,a=0,b; memset(vis,0,sizeof(vis)); for(i=1;i<=cnt;i++) { vis[num[i]]=1; } for(i=1;i<k;i++) { if(vis[e[i].u]&&vis[e[i].v]) { a++; } } a/=2; // cout<<cnt<<"wada"<<a<<endl; if(a>=cnt)sum+=a; //这里略有想不明白,写上之后水过去了。以后再研究 if(a>cnt){ ans+=a; }}void Tarjan(int u,int rt){ //我的Tarjan模版 int i,t; dfn[u]=low[u]=++dep; sta[++top]=u; insta[u]=1; for(i=head[u];i;i=e[i].nex){ int v=e[i].v; if(v==rt)continue; if(!dfn[v]){ Tarjan(v,u); low[u]=min(low[u],low[v]); if(dfn[u]<=low[v]){ ///要注意一个点可能同时属于不同的点双连通分量 cnt=0; do{ t=sta[top--]; insta[t]=0; num[++cnt]=t; }while(v!=t); num[++cnt]=u; getcont(); } } else{ if(insta[v])low[u]=min(low[u],dfn[v]); } }}void init(){ k=1; dep=1; top=atype=0; memset(insta,0,sizeof(insta)); //是否在栈中 memset(head,0,sizeof(head)); //静态链表头指针 memset(low,0,sizeof(low)); //Tarjan的low数组 memset(dfn,0,sizeof(dfn)); //Tarjan的dfn数组 memset(belon,0,sizeof(belon)); //记录每个点属于哪一个双连通分量}int main(){ int i,j,a,b; while(scanf("%d%d",&n,&m)!=EOF&&(n||m)){ init(); ans=sum=0; for(i=0;i<m;i++){ scanf("%d%d",&a,&b); a++,b++; addedge(a,b); addedge(b,a); }circuit for(i=1;i<=n;i++) { if(!dfn[i]) { Tarjan(i,-1); } } a=m-sum; printf("%d %d\n",a,ans); } return 0;}?