標籤:
題意:
有一幅圖,現在要加一條邊,加邊之後要你刪除一條邊,使圖不連通,費用為邊的費用,要你求的是刪除的邊的最小值的最大值(每次都可以刪除一條邊,選最小的刪除,這些最小中的最大就為答案)
首先要進行縮點,把圖縮為一棵樹,因此,加入一條邊後圖就會存在一個環,環中的任何一條邊刪除後都不會導致圖不連通
之後找一條最小的邊,可以說這條邊肯定是在加邊之後的連通塊裡的,因為如果不在連通塊裡,那就直接可以把這條最小的邊刪掉,而達不到求出答案的目的
找到邊後,分別從邊的兩點開始遍曆,要遍曆出一條路徑來,並且邊上的權值要儘可能的小,因為這樣才能讓不在環中的邊儘可能的大,然後,答案就是每個 節點的次小兒子的最小值,如果沒有次小兒子就不能算(就是說只有一個兒子,即節點不是三叉的),因為我完全可以把它和最小的邊放到一個連通塊中,那樣答案 就應該更大了。
終上所述:先進行無向圖的縮點,再在樹上找最小的邊,最後分別從邊的兩點出發,遍曆樹,找節點的次小兒子節點中的最小值
舉個簡單的例子(括弧內的數字代表邊上的權值)1和8間的權值為1,是最小的
1---8
/ \(3)
(2)/ \
2 3
(4) / \(5) (6)/ \(7)
/ \ / \
4 5 6 7
左子樹中2的子節點有次小值5,右子樹中3的子節點次小值為7,兩個次小值間的最小值是5,即答案
現在,比如所你要把3、4連起來。我可以去掉2、5之間的邊讓圖不連通,花費為5
把3、5連起來,我自然可以刪掉2、4,花費為4,
一個節點的次小值和最小值(比如說4、5兩點)不可能被同時連進一個連通塊(或環)中(因為必須把最小的那條邊加進環中),正是利用這個性質,不管 把那兩個點連起來,我們都可以找到一個最小值或次小值來刪掉使圖不連通,注意:再重複一遍,同一個節點的最小值和次小值不會被加進同一個環,因此,這些次 小值中的最小的那條邊的權值就是答案。(這時你如果把次小的邊加進環中,如2--5,自然可以刪掉一條更小的邊 如2--4 使圖不連通,相反,如果沒有把次小的邊加進去,那次小的就是答案)
思路是次要,代碼要能搞出來
1 #include<cstdio> 2 #include<cstring> 3 #include<stack> 4 #include<algorithm> 5 #define N 20100 6 #define M 200100 7 #define inf 100000000 8 #pragma comment(linker, "/STACK:1024000000,1024000000") 9 using namespace std; 10 int head1[N],head2[N],cnt,scc,Min; 11 int dfn[N],low[N],belong[N]; 12 int dp[N]; 13 stack<int>sta; 14 struct Edge{ 15 int v,w,next; 16 }edge[M*4]; 17 18 void addedge(int u,int v,int w,int *head){ 19 edge[cnt].v=v; 20 edge[cnt].w=w; 21 edge[cnt].next=head[u]; 22 head[u]=cnt++; 23 edge[cnt].v=u; 24 edge[cnt].w=w; 25 edge[cnt].next=head[v]; 26 head[v]=cnt++; 27 } 28 void init(int n){ 29 memset(head1,-1,sizeof(head1)); 30 memset(head2,-1,sizeof(head2)); 31 memset(dfn,0,sizeof(dfn)); 32 for(int i=1;i<=n;i++)dp[i]=inf; 33 cnt=scc=0; 34 } 35 void DP(int u,int fa){ 36 int i; 37 for(i=head2[u];i!=-1;i=edge[i].next){ 38 int v=edge[i].v; 39 if(v!=fa){ 40 DP(v,u); 41 dp[v]=min(dp[v],edge[i].w); 42 if(dp[u]>dp[v]){ 43 Min=min(Min,dp[u]); 44 dp[u]=dp[v]; 45 } 46 else 47 Min=min(Min,dp[v]); 48 } 49 } 50 } 51 void tarjan(int u,int fa){ 52 int i,flag=1; 53 dfn[u]=low[u]=dfn[fa]+1; 54 sta.push(u); 55 for(i=head1[u];i!=-1;i=edge[i].next){ 56 int v=edge[i].v; 57 if(v==fa && flag){ 58 flag=0; 59 continue; 60 } 61 if(dfn[v]==0){ 62 tarjan(v,u); 63 low[u]=min(low[u],low[v]); 64 } 65 else 66 low[u]=min(low[u],dfn[v]); 67 } 68 if(dfn[u]==low[u]){ 69 scc++; 70 while(1){ 71 int tem=sta.top(); 72 sta.pop(); 73 belong[tem]=scc; 74 if(tem==u)break; 75 } 76 } 77 } 78 int main(){ 79 int i,n,m; 80 int u,v,w; 81 while(scanf("%d %d",&n,&m)==2){ 82 init(n); 83 for(i=1;i<=m;i++){ 84 scanf("%d %d %d",&u,&v,&w); 85 addedge(u,v,w,head1); 86 } 87 for(i=1;i<=n;i++) 88 if(dfn[i]==0) 89 tarjan(1,0); 90 if(scc==1){ 91 printf("-1\n"); 92 continue; 93 } 94 int last=cnt,whi; 95 Min=inf; 96 for(i=0;i<last;i+=2){ 97 if(belong[edge[i].v]!=belong[edge[i^1].v]){ 98 addedge(belong[edge[i].v],belong[edge[i^1].v],edge[i].w,head2); 99 if(edge[i].w<Min){100 whi=i;101 Min=edge[i].w;102 }103 }104 }105 Min=inf;106 DP(belong[edge[whi].v],belong[edge[whi^1].v]);107 DP(belong[edge[whi^1].v],belong[edge[whi].v]);108 if(Min==inf)printf("-1\n");109 else printf("%d\n",Min);110 }111 return 0;112 }
hdu 4005 雙聯通 2011大連賽區網路賽E *****