標籤:strong images raw ons 需要 val 操作 style src
·從前有一個鴿子Lence,它吃了一個炸彈,然後有人出了這道題。
·英文題,述大意:
給出一張連通無向圖,求出:對於每個點,刪去這個點(以及它相連的邊以後)時,當前圖中的連通塊數量,這個值作為該點的Lence值。輸出根據Lence值從大到小(相同時標號從小到大)的前m個點和它的Lence值。
·分析:
關於連通塊問題,可以尋得三種方法:
①嘎嘣脆演算法(Gabow)②塔爾楊演算法(Tarjan)③Kosaraju演算法。
此處大米餅採用Tarjan演算法。
·幹什麼呢?尋找並標記雙連通分量。
在無向圖中發現一個雙連通分量(這裡指邊點連通分量)的意義:就算你任意吃掉一個點,這其中的點依然可以互相到達,也就是所謂的連通塊。如果我們將一個圖劃分為多個雙聯通分量,就是這樣:
·為了方便觀賞,使用縮點操作。就是這樣:
·所以,我們的方法是:根據點的位置進行分類處理。如果這個點不與橋串連,那麼整個圖還是聯通的。如果該點和橋相連,那我們就猜一猜它和幾座橋相連(不是猜,認真算!),那麼它的毀滅會帶來這些橋的毀滅,每一座橋的毀滅會使得一個雙聯通分量脫離原圖,所以:如果這個點串連了num座橋,那麼現在這個圖就成了風雨飄蕩中的(num+1)個部分。
·注意,在實際處理時,我們是用數組記錄下每個點串連的橋的個數,所以如果這點不與橋相連,那麼就是0,最終答案為0+1=1,因此不需要特殊處理。美妙的模板is drawing closer!
1 #include<stdio.h> 2 #include<algorithm> 3 #include<cstring> 4 #define go(i,a,b) for(int i=a;i<=b;i++) 5 #define fo(i,a,x) for(int i=a[x],v=e[i].v;i;i=e[i].next,v=e[i].v) 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 using namespace std;const int N=10003; 8 struct E{int v,next;}e[N*100];struct A{int u,val;}ans[N];bool Cut[N]; 9 int n,m,head[N],k,low[N],dfn[N],t,dfs_clock;10 bool cmp(A a,A b){return a.val==b.val?a.u<b.u:a.val>b.val;}11 void ADD(int u,int v){e[k]=(E){v,head[u]};head[u]=k++;}12 void Tarjan(int u,int fa)13 {14 low[u]=dfn[u]=++dfs_clock;int num=0,kids=0;15 fo(i,head,u)if(v!=fa){if(!dfn[v])16 {17 kids++;Tarjan(v,u);low[u]=min(low[u],low[v]);18 if(dfn[u]<=low[v])num++,Cut[u]=1;}//錯寫成low[u] 19 else low[u]=min(low[u],dfn[v]);20 }21 if(!fa&&kids==1)Cut[u]=0,num=0;ans[++t]=(A){u,num};22 }23 int main(){while(scanf("%d%d",&n,&m)&&n)24 {25 mem(head,0);mem(low,0);mem(dfn,0);mem(Cut,0);t=dfs_clock=0;k=1;int u,v;26 while(scanf("%d%d",&u,&v)&&++u&&++v)ADD(u,v),ADD(v,u); 27 go(i,1,n)if(!dfn[i])Tarjan(i,0);sort(ans+1,ans+t+1,cmp);28 go(i,1,m)printf("%d %d\n",ans[i].u-1,ans[i].val+1);29 puts("");}return 0;}//Paul_Guderian
讓我,感到為難的,是掙紮的自由。————趙雷《成都》
【吃炸彈的鴿子UVA10765-雙聯通模板】