最小度限制生成樹

2022-05-05 21:45:13 字數 3027 閱讀 8940

黑書+**+各種資料。終於理解了一點。。。

最小度限制生成樹就是給乙個圖,讓求它的最小生成樹。找的的最小生成樹滿足並且點vo的度最大為k。

演算法流程如下:

1.將該點(以下用v0表示)從圖中刪除,將得到m個連通分量。

2.對每個連通分量求最小生成樹,假設m個。

3.從每個連通分量中找與v0關聯的權值最小的邊,與v0相連線,這樣將得到v0的最小m度生成樹

4.如果 k  < m 那麼這種樹是不存在的。

5.如果 k >=m ,那麼考慮構建 m+1度 最小生成樹 ,將與v0關聯的且不在當前的樹中的邊

6.如果將其加入樹中 ,必然會存在乙個環,那麼刪掉該環中與v0不關聯的權值最大邊,將得到加入該邊後的最小生成樹,且是m+1的。

7.列舉上述 6 的邊找樹權值最小,那麼即是m+1度限制的最小生成樹。如果 m + 1 度最小生成樹的值大於 m 度最小生成樹的話直接輸出當前 m  度的值即可。

8.重複5.6.7,直到k 度最小生成樹出現。

由於從度為m擴充套件到m+1時存在大量的重複計算,可以用動態規劃優化。

以下引用自汪汀的**

由最小m度限制生成樹,得到最小m+1度限制生成樹,對於和v0相鄰的點v,則可以知道一定會有乙個環出現,只要找到這個環上的最大權邊,用邊(v0, v)替換掉,就可以得到乙個m+1度限制生成樹,列舉所有和v0相鄰點v,找到替換後增加權值最小的一次替換,就可以求得m+1度限制生成樹。。如果每新增一條邊,都需要對環上的邊一一枚

舉,時間複雜度將比較高,這裡,動態規劃就有了用武之地。設best(v)為路徑v0—v上與v0無關聯且權值最大的邊。定義father(v)為v的父結點,動態轉移方程:best(v)=max(best(father(v)),ω(father(v),v)),邊界條件為best[v0]=-∞,best[v』]=-∞| (v0,v』)∈e(t)。

模板poj 1639:

#include #include 

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define cl(arr, val) memset(arr, val, sizeof(arr))

#define rep(i, n) for((i) = 0; (i) < (n); ++(i))

#define for(i, l, h) for((i) = (l); (i) <= (h); ++(i))

#define ford(i, h, l) for((i) = (h); (i) >= (l); --(i))

#define l(x) (x) << 1

#define r(x) (x) << 1 | 1

#define mid(l, r) (l + r) >> 1

#define min(x, y) x < y ? x : y

#define max(x, y) x < y ? y : x

#define e(x) (1 << (x))

const

double eps = 1e-8

;typedef

long

long

ll;using

namespace

std;

const

int inf = ~0u>>2

;const

int n = 33

;int

parent[n];

intg[n][n];

bool

flag[n][n];

mapnum;

intn, k, cnt, ans;

struct

node a[

1<<10

];struct

edge dp[n];

bool

cmp(node a, node b)

int find(int x)

returnr;}

int get_num(string s)

return

num[s];

}void kruskal()

//printf("%d\n", ans);

}void dfs(int x, int pre)

}dfs(i, x);}}

}void

init()

intmain()

scanf("%d

", &k);

intset

[n], min[n];

rep(i, n) min[i] =inf;

sort(a + 1, a + n + 1

, cmp);

kruskal();

for(i,

2, cnt) }}

int m = 0

; for(i,

1, cnt)

}//printf("%d\n", ans);

for(i = m + 1; i <= k; ++i)

dfs(

1, -1

);

int tmp, mi =inf;

for(j = 2; j <= cnt; ++j) }}

if(mi >= 0) break; //

如果不存在這樣的邊,直接退出

int x = dp[tmp].x, y =dp[tmp].y;

flag[

1][tmp] = flag[tmp][1] = true; //

加上新找的邊

flag[x][y] = flag[y][x] = false; //

刪掉被替換掉的那條邊

ans +=mi;

}printf(

"total miles driven: %d\n

", ans);

return0;

}

最小度限制生成樹

最小度限制生成樹 具體講解和證明,黑書上有,ioi2004國家集訓隊 王汀 中也有講解,這裡簡單介紹求法過程。為了方便敘述,把頂點v0的度數 k稱作度限制條件,把滿足這一條件的生成樹稱為度限制生成樹,把權值和最小的度限制生成樹稱為最小度限制生成樹。要求的最小k度生成樹,應該有以下的步驟 演算法框架 ...

最小度限制生成樹

在一棵生成樹中,某個頂點v0的度數 k稱作度限制條件,把滿足這一條件的生成樹稱為度限制生成樹,把權值和最小的度限制生成樹稱為最小度限制生成樹。如果撇開度限制條件,那麼就是最小生成樹問題。首先,避開度限制條件。假如把最小度限制生成樹中所有與v0相關的邊都刪掉,得到m個連通分量。具體步驟 1.如果k 2...

ACM 最小度限制生成樹

最小度限制生成樹是指某乙個節點的度限制為k的最小生成樹。具體的做法去看 或者黑書吧,這裡不詳細講了。理解最小度限制生成樹的解法,最主要的就是看懂如何由m度生成樹求m 1度生成樹,另外要理解無解的情況。今天終於把模板整理出來了,prim那裡用了優先佇列優化,新增刪除邊破環那裡用的是動態規劃。試了試pk...