在一棵生成樹中,某個頂點v0的度數<=k稱作度限制條件,把滿足這一條件的生成樹稱為度限制生成樹,把權值和最小的度限制生成樹稱為最小度限制生成樹。
如果撇開度限制條件,那麼就是最小生成樹問題。首先,避開度限制條件。假如把最小度限制生成樹中所有與v0相關的邊都刪掉,得到m個連通分量。
具體步驟:
1. 如果k
2. 求最小m度限制生成樹。
3. 有最小m度限制生成樹求最小m+1度限制生成樹。
4. 當dt(v0)==k時,停止迭代。
說明:
求最小m度限制生成樹時:去掉圖中和v0相連的所有邊,得到m個連通分量,而這m個連通分量必須通過v0來連線。所以在生成樹中,dt(v0)>=m,如果k
由最小m度限制生成樹得到最小m+1度限制生成樹:對於和v0相鄰的點v,新增後一定會形成乙個環,找到環上權值最大的邊,用(v0,v)替換掉。列舉所有和v0相鄰的點,找到權值增加最小的一次替換,就可以得到最小m+1度限制生成樹。每次列舉的時候都需要找換上不和v0相連的最大邊,需要用到動態規劃:設best[v]是v0到v路勁上不與v0相連的最大邊,定義father[v]是v的父節點,狀態轉移方程為:
best[v] = max
邊界條件為best[v0]=inf,best[v']=inf((v0,v')是圖中的邊)。
模型與例題:
1. 考慮下面這個問題:
問怎樣合理的分配衛星和鋪設線路,使得任意兩個村莊都能直接或間接通訊,並且鋪設線路最短,求最短的線路是多少。n,k<=5000
解:如果不設衛星,就相當於求原圖的最小生成樹。如何改造該模型?增設乙個點v0,和所有村莊相連,權值為0,該圖的乙個最小生成樹就對應著一種方案,鋪設路線長度為對應的生成樹的權值之和,生成樹中與v0相關的村莊為安放衛星的村莊。這樣問題轉化為求dt(v0)==k的最小生成樹問題了。
2. poj1639
題意:一些人準備去公園開party,每個人可以開車直接去或者把車開到a家,然後做a的車到公園,每輛車可以座無數個人,但公園最多只能停放k輛車。問所有人開車的路程之和最短為多少。
解:把公園點v0看成度限制條件,求所有<=k的度限制生成樹,取最小值即可。
/*
最小度限制生成樹
*/#include #include #include using namespace std;
const int inf = 0x7fffffff;
const int n = 30;
int n,s,k; //節點總數 有度數限制的點v0 度數限制為k
int mst; //最終結果:最小k限制度生成樹
int mp[n][n]; //圖
int father[n]; //節點n的父節點
bool edge[n][n]; //判斷邊(i,j)是否加入到生成樹中
int best[n]; //從v0到v路徑上與v0無關的最大權邊的點序號
char str[n][12];
int dis[n];
bool mark[n];
bool vis[n];
int pre[n];
void dfs(int now)
}}int prim(int s) //從點s開始的最小生成樹
while(true)
}if(min == inf) break;
mark[key] = true;
vis[key] = true;
edge[pre[key]][key] = edge[key][pre[key]] = true;
sum += min;
for(i = 0; i < n; i++)}}
min = inf;
int root = -1; //找到與v0相關聯的點的最小邊
for(i = 0; i < n; i++)
}mark[root] = false;
dfs(root); // 將樹拉成有根樹
father[root] = s;
return sum + min;
}int best(int x) //記憶化搜尋s到x的最大權值的邊
int find(char *c)
return -1;
}void input()
int y = find(s2);
if(y == -1)
if(w < mp[x][y]) //可能有重邊
mp[x][y] = mp[y][x] = w;
}scanf("%d",&k);
}void solve()
}int change; // 回路上權值最大的邊,用於交換
int ax,bx,tmp;
for(i = m+1; i <= k && i < n; i++)
int minadd = inf; // 交換邊的最小差值
for(j = 0; j < n; j++)}}
if (minadd >= 0) break; //用於度數不大於k的限制,如果k限制,就不用break了
mst += minadd;
ax = best[change];
bx = father[ax];
mp[ax][bx] = mp[bx][ax] = inf;
father[ax] = bx = s; // 改變生成樹,將點ax直接指向源點s
mp[ax][s] = mp[s][ax] = mp[change][s];
mp[s][change] = mp[change][s] = inf;
}}int main()
最小度限制生成樹
最小度限制生成樹 具體講解和證明,黑書上有,ioi2004國家集訓隊 王汀 中也有講解,這裡簡單介紹求法過程。為了方便敘述,把頂點v0的度數 k稱作度限制條件,把滿足這一條件的生成樹稱為度限制生成樹,把權值和最小的度限制生成樹稱為最小度限制生成樹。要求的最小k度生成樹,應該有以下的步驟 演算法框架 ...
最小度限制生成樹
黑書 各種資料。終於理解了一點。最小度限制生成樹就是給乙個圖,讓求它的最小生成樹。找的的最小生成樹滿足並且點vo的度最大為k。演算法流程如下 1.將該點 以下用v0表示 從圖中刪除,將得到m個連通分量。2.對每個連通分量求最小生成樹,假設m個。3.從每個連通分量中找與v0關聯的權值最小的邊,與v0相...
ACM 最小度限制生成樹
最小度限制生成樹是指某乙個節點的度限制為k的最小生成樹。具體的做法去看 或者黑書吧,這裡不詳細講了。理解最小度限制生成樹的解法,最主要的就是看懂如何由m度生成樹求m 1度生成樹,另外要理解無解的情況。今天終於把模板整理出來了,prim那裡用了優先佇列優化,新增刪除邊破環那裡用的是動態規劃。試了試pk...