圖算法之(割邊/橋)
阿新 • • 發佈:2017-09-26
efi ace and fclose 開始 無向圖 訪問 fine n) 7 1
7 2
7 3
7 5
8 2
9 6
10 8
輸出:
3
2 8
6 9
8 10
樣例第一行兩個數分別表示點數和邊數,接下來M行表示M條邊。輸出第一行為橋的個數,接下來每行兩個數表示橋。
棧裏面的點,它在整個過程中始終是從根到當前點的一條鏈。
在所有訪問過的點(紅點和綠點)中,只有它們是可能擴展出未被訪問的點的。
所以當一個點(設為u)退棧的時候,考慮假設以這個點為根,能遍歷到的點組成的集合,只會有兩種情況:
1. 這個點已經被訪問過了(變成紅色或者綠色)
2. 這個點(設為v)還是黑色的,但是一定存在另一個紅點(設為x),能夠在不走紅邊的情況下訪問到它,即
一定存在一條路徑 u=>x=>v;
給定無向圖的點(N)和邊(M),輸出圖中所有的橋(按小編號排序)。
N<=2000
註意:重邊算一條
輸入:
10 17
2 1
2 6
2 8
3 2
3 5
4 2
4 7
5 3
5 4
6 3
7 2
7 3
7 5
8 2
9 6
10 8
輸出:
3
2 8
6 9
8 10
樣例第一行兩個數分別表示點數和邊數,接下來M行表示M條邊。輸出第一行為橋的個數,接下來每行兩個數表示橋。
這道題,暴力不說了,直接說正規算法
定理:一個邊是割邊當且僅當他是樹邊並且他的開始節點的時間戳小於其後繼節點的子樹的所能找到的最早的節點。
自己證明。(*^▽^*)=>(#`O′)=>(╯‵□′)╯︵┻━┻
#include<cstdio> #include<cstring> #include<algorithm> #define N 2000+10 usingnamespace std; int head[N],num; struct edge{ int next,to; }; struct data{ int x,y; }; data ss[2*N*(N-1)]; edge e[2*N*(N-1)]; void add(int from,int to) { e[++num].next=head[from]; e[num].to=to; head[from]=num; } int flag[N],dfn[N],low[N]; int bu[N],bv[N]; int tim=0,tot; int cnt=0; int cmp(const data & a,const data & b) { if(a.x<b.x)return 1; if(a.x>b.x)return 0; if(a.y<b.y)return 1; return 0; } void tarjan_CE(int u,int fa) { //vis[u]=1; tim++; low[u]=dfn[u]=tim; // int son=0; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; //if(v==fa)continue; if(!dfn[v]) { // son++; tarjan_CE(v,u); low[u]=min(low[u],low[v]); if(low[v]>dfn[u]) { ss[++cnt].x=u,ss[cnt].y=v; } //flag[u]=1; // if(u==root&&son>=2) // { // ss[++cnt].x=u,ss[cnt].y=v; // } } else if(v!=fa) { low[u]=min(low[u],dfn[v]); } } return; } int main() { // freopen("sss.in","r",stdin); // freopen("sss.out","w",stdout); int n,m; scanf("%d%d",&n,&m); int x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); // if(!book[x][y]and!book[y][x]) // { add(x,y); add(y,x); // book[x][y]=book[y][x]=1; // } } cnt=0; tarjan_CE(1,1); sort(ss+1,ss+cnt+1,cmp); // for(int i=1;i<=n;i++) // { // if(flag[i]==1)cnt++; // //printf("%d ",i); // } printf("%d\n",cnt); for(int i=1;i<=cnt;i++) { //if(!book[ss[i].x][ss[i].y]&&!book[ss[i].y][ss[i].x]) printf("%d %d\n",ss[i].x,ss[i].y); //book[ss[i].x][ss[i].y]= book[ss[i].y][ss[i].x]=1; } // fclose(stdout); return 0; }
圖算法之(割邊/橋)