[校內模擬]最小生成樹(Tarjan)
=== ===
=== ===
題解
ATP當時考試考這題的時候就寫了個暴力還寫掛了。。。
首先聯想Kruskal的操作過程可以想到,對於一條權值為w的邊(u,v),如果權值小於它的邊已經聯通了u和v,那麼這條邊就一定不會被加到最小生成樹裡面;如果再加上除了(u,v)以外其它權值等於w的邊就能把u和v聯通,那麼這條邊就可能出現在某棵最小生成樹裡面;否則就說明想要把u和v聯通,這條邊是必須的,也就是它一定出現在所有最小生成樹裡面。
none的情況非常好判,重點就是判後兩種情況。對於at least one的情況來說肯定不能每次列舉某條邊加不加,就要一下全判出來。可以發現那些any的邊,它是小於等於w的所有邊裡面聯通(u,v)的必須邊,去掉這條邊,圖就會不連通。
有沒有想到什麼啊對吧= =沒錯這就是無向圖中的橋邊!每次把和w權值相等的邊加入進去,並且需要注意的是因為前面處理完小於w的邊了以後圖中已經有了一些連通塊,所以加邊的時候不是直接連線u和v,而是連線find(u)和find(v),即u和v在集合中的代表元素。那麼顯然如果列舉到某條邊的時候它的兩個端點已經在同一個連通塊中了,說明小於它的邊就可以聯通它兩個端點,就判成none就可以了。然後構造出這個圖以後裡面所有的橋邊就是any,剩下的就是at least one啦。
注意的問題是每次都要重新構圖,清陣列的時候需要注意。不能用memset否則會T飛的啦。用一個點清一個點就可以了。
程式碼
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,tot,cnt,dfc,father[100010],w[100010],low[100010],last[100010],p[100010];
int next[200010],a[200010],ans[100010],rec[100010],id[100010];
bool vis[100010];
struct edge{
int x,y,w,id;
}e[100010];
int comp(edge a,edge b){return a.w<b.w;}
void add(int x,int y,int i){
tot++;a[tot]=y;next[tot]=p[x];id[tot]=i;p[x]=tot;
}
int find(int x){
if (father[x]==x) return father[x];
father[x]=find(father[x]);
return father[x];
}
bool same(int i,int j){
if (i%2==0) return i-1==j;
else return i+1==j;
}
void tarjan(int u){
w[u]=low[u]=++dfc;vis[u]=true;
for (int i=p[u];i!=0;i=next[i])
if (vis[a[i]]==false){
last[a[i]]=i;
tarjan(a[i]);
low[u]=min(low[u],low[a[i]]);
}else if (!same(last[u],i)) low[u]=min(low[u],w[a[i]]);
}//注意在判是不是同一條邊的時候,無向邊加的正反邊要算同一條
void check(){
for (int i=1;i<=cnt;i++)
if (w[rec[i]]==0)
tarjan(rec[i]);
for (int i=1;i<=cnt;i++){
int u=rec[i];
if (low[u]==w[u])
ans[id[last[u]]]=2;
}
for (int i=1;i<=cnt;i++)
for (int j=p[rec[i]];j!=0;j=next[j])
if (ans[id[j]]==0) ans[id[j]]=1;
}
int main()
{
freopen("mst.in","r",stdin);
freopen("mst.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++){
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
e[i].id=i;
}
sort(e+1,e+m+1,comp);
memset(w,-1,sizeof(w));
for (int i=1;i<=n;i++) father[i]=i;
for (int i=1;i<=m;){
int tail=i;tot=cnt=dfc=0;
while (e[tail].w==e[i].w){
int r1,r2;
r1=find(e[tail].x);r2=find(e[tail].y);
if (r1!=r2){
if (w[r1]!=0){//注意rec和p都只能初始化一次,尤其是p
rec[++cnt]=r1;p[r1]=0;
}
if (w[r2]!=0){
rec[++cnt]=r2;p[r2]=0;
}
w[r1]=w[r2]=0;
low[r1]=low[r2]=last[r1]=last[r2]=0;
vis[r1]=vis[r2]=false;
add(r1,r2,e[tail].id);add(r2,r1,e[tail].id);
}//加邊
tail++;
}
check();
for (int j=i;j<tail;j++){
int r1,r2;//把處理完的邊加到並查集裡
r1=find(e[j].x);r2=find(e[j].y);
if (r1!=r2) father[r2]=r1;
}
i=tail;
}
for (int i=1;i<=m;i++)
if (ans[i]==0) printf("none\n");
else if (ans[i]==1) printf("at least one\n");
else printf("any\n");
return 0;
}
相關推薦
[校內模擬]最小生成樹(Tarjan)
=== === === === 題解 ATP當時考試考這題的時候就寫了個暴力還寫掛了。。。 首先聯想Kruskal的操作過程可以想到,對於一條權值為w的邊(u,v),如果權值小於它的邊已經聯通了u和v,那麼這條邊就一定不會被加到最小生
POJ 2485 Highways 最小生成樹 (Kruskal)
between all pac pair content cross cte reel sca Description The island nation of Flatopia is perfectly flat. Unfortunately, Flatopia
還是暢通工程——最小生成樹(王道)
不一定 要求 LG sin 最小生成樹 bsp 生成樹 結束 operator 題目描述: 某省調查鄉村交通狀況,得到的統計表中列出了任意兩村莊間的距離。省政府“暢通工程”的目標是使全省任何兩個村莊間都可以實現公路交通(但不一定有直接的公路相連,只要能間接通過公路可
【複習】---【p2820】區域網--洛谷//最小生成樹 (2)
題目背景某個區域網內有n(n<=100)臺計算機,由於搭建區域網時工作人員的疏忽,現在區域網內的連線形成了迴路,我們知道如果區域網形成迴路那麼資料將不停的在迴路內傳輸,造成網路卡的現象。因為連線計算機的網線本身不同,所以有一些連線不是很暢通,我們用f(i,j)表示i,j之間連線的暢通程度,f(i,j)值
最小生成樹(模板)
luogu 3366 模板如下: #include <bits/stdc++.h> #define ll long long #define N 200005 using namespace std; int fa[N]; struct node { int l,r,va
資料結構——圖(8)——最小生成樹(MST)
問題的提出 如下圖,假設這裡有一系列的房屋,問如何鋪設電線,可以使得連線所有房屋的電線的總成本最低?這是20世紀20年代早期研究最小生長樹的最初動機。 (捷克數學家OtakarBorůvka完成的工作)。 最短路徑樹與最小生成樹(MST) 上次,我們看到了Dijkstra演
最小生成樹(MST)之Kruskal
題目大意 給定一個 n n n個點m條邊的無向圖
資料結構 筆記:最小生成樹(prim)
運營商的挑戰 -在下圖標出的城市間架設一條通訊線路 要求: ·任意兩個城市間都能夠通訊 ·將架設成本呢將至最低 如何在圖中選擇n-1條邊使得n個頂點間兩兩可達,並且這n-1條邊的權值之和最小 最小生成樹 -僅使用圖中的n-1條邊連線圖中的n個頂點
最小生成樹(MST)
目錄 一、知識點 二、例題 一、知識點 1. 生成樹定義:在一個有n個點的無向連通圖中,取其n-1條邊並連線所有的頂點,所得到的子圖稱為原圖的一棵生成樹。 2. 樹的屬性:無環+連通+任意兩點之間只有唯一的簡單路徑+刪掉任意邊就不連通 3. 最小生成樹:各邊權和最小的一棵
資料結構 筆記:最小生成樹(Kruskal)
最小生成樹的特徵: -選取的邊是圖中權值較小的邊 -所有邊連線後不構成迴路 既然最小生成樹關心的是如何選擇n-1條邊,那麼是否可以直接以邊為核心進行演算法設計? -由4個頂點構成圖,選擇3條權值最小的邊 如何判斷新選擇的邊與已選擇的邊是否構成迴路? 技巧:前驅標記陣列 -
最小生成樹(Kruskal)
#include<iostream> #include<cstdio> #include<vector> #include<algorithm> using namespace std; int flag = 0; struct
動態維護最小生成樹(IOI2003Maintain)
WOJ2235 Maintain 描述 農夫約翰的奶牛們希望能夠在農場的N(1<=N<=200)塊田地中自由的旅遊,儘管這些田地被樹林分開了。他們希望能夠通過維護一對對田地間的路徑使得任意兩塊田地間都有通路。奶牛們可以沿著任一方向的維護的路徑旅遊。
資料結構作業15—圖的遍歷與最小生成樹(選擇題)
2-1給定有權無向圖如下。關於其最小生成樹,下列哪句是對的? (3分) A.邊(B, F)一定在樹中,樹的總權重為23 B.邊(H, G)一定在樹中,樹的總權重為20 C.最小生成樹唯一,其總權重為20 D.最小生成樹不唯一,其總權重為23
最小生成樹(kruskal)Codeforces 472D
There is an easy way to obtain a new task from an old one called "Inverse the problem": we give an output of the original task, and ask to generate an inp
最小生成樹(MST)的性質及演算法 [轉】
轉自: 最小生成樹性質1:設G=(V,E)是一個連通網路,U是頂點集V的一個真子集。若(u,v)是G中所有的一個端點在U(u∈U)裡、另一個端點不在U(即v∈V-U)裡的邊中,具有最小權值的一條邊,則一定存在G的一棵最小生成樹包括此邊(u,v)。 證明: 為方便說明
python機器學習案例系列教程——最小生成樹(MST)的Prim演算法和Kruskal演算法
最小生成樹MST 一個有 n 個結點的連通圖的生成樹是原圖的極小連通子圖,且包含原圖中的所有 n 個結點,並且有保持圖連通的最少的邊。 也就是說,用原圖中有的邊,連線n個節點,保證每個節點都被連線,且使用的邊的數目最少。 最小權重生成樹 在一給定
最小生成樹(Dijkstra)演算法和最短路(Prim)演算法的異同
Prim演算法用於構建最小生成樹——即樹中所有路徑之和最小,但不能保證任意兩點之間是最短路徑。例如,構建電路板,使所有邊的和花費最少。只能用於無向圖。Dijkstra演算法用於構建(MST)——即樹中指
最小生成樹(二)--prim演算法實現以及堆優化
一、最小生成樹---prim演算法實現 思想: 1、從任意一個頂點開始構造生成樹,假設就從1號頂點吧, 首先將頂點1加入生成樹中,用一個一維陣列book來標記 哪些頂點已經加入了生成樹。 2、用陣列dis記錄生成樹到各個頂點的距離,最初生成樹中之後1號 頂點,有直連邊時,
最小生成樹(1)--Kruskal演算法
圖的最小生成樹 圖的最小生成樹,是指用最小的邊讓圖連通,讓任意兩點之間可以互相到達。圖如果有n個頂點,則應該有n-1條邊。此時連通無向圖沒有迴路,就是一顆樹,所以稱為最小生成樹。 最小生成樹是讓邊的總長度之和最短,其中一種方法是可以選擇最短的邊,然後依次
最小生成樹(例子)
N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。Input第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N <= 1000, 1 <= M <= 50000) 第2 - M + 1行:每行3個數S E W,