給定一張n
nn個點m
mm條邊的無向圖,求無向圖的嚴格次小生成樹。
設最小生成樹的邊權之和為sum
sumsu
m ,嚴格次小生成樹就是指邊權之和大於sum
sumsu
m的生成樹中最小的乙個。
先建出一棵最小生成樹,滿足使用的邊都是最小的,剩下的邊(稱為非樹邊)一定沒有樹邊優。如果我們加入一條非樹邊,刪除最小生成樹中的一條邊,次小生成樹一定是包括在以這種方法建出的樹中的。
證明:既然次小生成樹s
ss比某個生成樹大,不妨設這個生成樹是t
tt。t
tt一定可以用s
ss替換一條邊得到(否則說明s
ss是mst
mstms
t),此時若t
tt不是mst
mstms
t,則存在比t
tt更小的生成樹,與s
ss是次小生成樹矛盾。所以t
tt是mst
mstms
t。所以s
ss由最小生成樹t
tt加入一條非樹邊,刪除最小生成樹中的一條邊得來。
得證。列舉加入的非樹邊,先加入,由於刪除一條邊後仍是生成樹,所以只能刪掉環中任意一條邊,刪除環中最大邊顯然最優(這條邊一定小於等於新加的邊),將每種情況遍歷後取最小值,就是次小生成樹。特別的,若環中最大邊=新加的邊,則取次小邊。
該部分時間複雜度o(n
2)
o(n^2)
o(n2
),可以用lca倍增演算法優化到o(n
∗log
n)
o(n*logn)
o(n∗lo
gn)
演算法流程:
kruskal求出mst,將樹中的邊加入vector
從1節點開始執行bfs,求出深度、最大值、次大值、父節點
加入非樹邊(x,y,z),求出u=lac(x,y),從x到u,u到y的路徑中求最大值、次大值,然後更新ans=min(ans,sum+z-max)
輸出答案ans
#include
using
namespace std;
const
int n=
1e5+5;
const
int m=3*
1e5+5;
struct rec
}e[m]
;struct edge
;void
read
(int
&x)while
(c>=
'0'&&c<=
'9')
x*=f;
}int n,m,t,fa[n]
;int f[n][30
],d[n]
,dist[n][30
],dis[n][30
];long
long ans,sum;
bool used[n]
;vector son[n]
;queue<
int> q;
intfind
(int x)
intlca
(int x,
int y)
void
kruskal()
);son[y]
.push_back
((edge));
used[i]=1
;}}}
void
bfs(
) q.
push
(v);}}
}int
work
(int x,
int y,
int z)
else min=
max(min,dist[x]
[i])
; x=f[x]
[i];}}
dep=d[y]
-d[fat]
;for
(int i=
0;i<=t;i++
)else min=
max(min,dist[y]
[i])
; y=f[y]
[i];}}
if(max==z)
return min;
else
return max;
}int
main()
kruskal()
;bfs()
;for
(int i=
1;i<=m;i++)if
(!used[i]
)printf
("%lld"
,ans)
;}
仔細思考一下,本題就好像從第k小生成樹反過來求最小生成樹,然而真的成立嗎?本題n<=30,但是如果n更大,恐怕就要想更強力的貪心了。 最小生成樹 次小生成樹
一 最小生成樹 說到生成樹首先要解釋一下樹,樹是乙個聯通的無向無環圖,多棵樹的集合則被稱為森林。因此,樹具有許多性質 1.兩點之間的路徑是唯一的。2.邊數等於點數減一。3.連線任意兩點都會生成乙個環。對於乙個無向聯通圖g的子圖,如果它包含g的所有點,則它被稱為g的生成樹,而各邊權和最小的生成樹則被稱...
最小生成樹 次小生成樹 模板
次小生成樹我的理解 在最小生成樹的基礎上,列舉不再最小生陳樹上的邊,然後成環,取出一條除了新加入的那條邊外的最長邊,最終的權值即為次小生成樹的權值。小結論 當次小生成樹的權值與最小生成樹的權值相同時,最小生成樹不唯一。include include include includeusing name...
最小生成樹與次小生成樹
題意 給出兩個不同方案,每個方案使得所有的城堡被連通 形成連通圖 同時使邊權之和盡量小,問第乙個方案與第二個方案的大小關係。解題思路 因為m個橋能使n個城堡聯通,而兩個大爺的方案中至少存在乙個橋不相同,那麼我們判斷這是乙個求次小生成樹的方法。求次小生成樹模板 列舉 刪邊 再求mst複雜度有點高,看題...