黑書+**+各種資料。終於理解了一點。。。
最小度限制生成樹就是給乙個圖,讓求它的最小生成樹。找的的最小生成樹滿足並且點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...