业界萌新对斯坦纳树的小结
業界萌新對斯坦納樹的小結
0.簡介
斯坦納樹問題是組合優化問題,與最小生成樹相似,是最短網絡的一種。最小生成樹是在給定的點集和邊中尋求最短網絡使所有點連通。而最小斯坦納樹允許在給定點外增加額外的點,使生成的最短網絡開銷最小。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?——百度百科
簡單來講,斯坦納樹問題一般就是給定一個n個點m條邊的帶非負權無向圖,其中有k個關鍵點,要求選取一個子圖,讓所有關鍵點聯通,而最小斯坦納樹則在斯坦納樹的前提下,讓總費用最小。
在此推薦一位學長的文章,寫得很不錯:詳解斯坦納點及斯坦納樹及模版歸納總結。
?
1.最小斯坦納樹的求解方法
斯坦納樹只要求k個關鍵點聯通,顯然不能夠直接用最小生成樹的方法解決。
- 結論:最優解的方案一定會選取一棵樹。
- 證明:可行解顯然是一個連通圖,而如果圖上存在一個環,費用為。我們可以將其中最長的一條邊去掉,使得新費用,由于,所以。因此只會選取一棵樹。
這樣選取一棵樹求最優解的問題,常見的思路是。
?
2.具體實現
2.1狀態??
? ?表示以為根,關鍵點的選取狀態為??的最優費用。
2.2轉移
兩重轉移方程:
第一重轉移,更新新的選取狀態:?,?
第二重轉移,松弛新的選取狀態:
由于之后的選取狀態會由第一重轉移更新,所以只需要對當前的選取狀態進行松弛即可。
第一重轉移直接,第二重轉移用松弛
(PS:一般出題人不會在此處卡,但如果路遇毒瘤出題人黑心卡,還是用吧)。
時間復雜度顯然:,c是的常數,E是邊數。
2.3細節與技巧:
?
- 倘若每一次都全圖松弛會產生大量冗余運算,只需要對當前層節點進行松弛。
- 子集枚舉時可以用:? ?and表示位運算的與。
3.一個例題:[WC2008][luoguP4294]游覽計劃
題目描述
從未來過紹興的小D有幸參加了Winter Camp 2008,他被這座歷史名城的秀麗風景所吸引,強烈要求游覽紹興及其周邊的所有景點。
主辦者將紹興劃分為N行M列(N×M)個分塊,如下圖(8×8):
景點含于方塊內,且一個方塊至多有一個景點。無景點的方塊視為路。
為了保證安全與便利,主辦方依據路況和治安狀況,在非景點的一些方塊內安排不同數量的志愿者;在景點內聘請導游(導游不是志愿者)。在選擇旅游方案時,保證任意兩個景點之間,存在一條路徑,在這條路徑所經過的每一個方塊都有志愿者或者該方塊為景點。既能滿足選手們游覽的需要,又能夠讓志愿者的總數最少。
例如,在上面的例子中,在每個沒有景點的方塊中填入一個數字,表示控制該方塊最少需要的志愿者數目:
圖中用深色標出的方塊區域就是一種可行的志愿者安排方案,一共需要20名志愿者。由圖可見,兩個相鄰的景點是直接(有景點內的路)連通的(如沈園和八字橋)。
現在,希望你能夠幫助主辦方找到一種最好的安排方案。
輸入輸出格式
輸入格式:
第一行有兩個整數,N和M,描述方塊的數目。
接下來N行,每行有M個非負整數,如果該整數為0,則該方塊為一個景點;
否則表示控制該方塊至少需要的志愿者數目。相鄰的整數用(若干個)空格隔開,
行首行末也可能有多余的空格。
輸出格式:
由N+1行組成。第一行為一個整數,表示你所給出的方案中安排的志愿者總數目。
接下來N行,每行M個字符,描述方案中相應方塊的情況:
'_'(下劃線)表示該方塊沒有安排志愿者;
'o'(小寫英文字母o)表示該方塊安排了志愿者;
'x'(小寫英文字母x)表示該方塊是一個景點;
注:請注意輸出格式要求,如果缺少某一行或者某一行的字符數目和要求不一致(任何一行中,多余的空格都不允許出現),都可能導致該測試點不得分。
輸入輸出樣例
輸入樣例#1:
4 4
0 1 1 0
2 5 5 1
1 5 5 1
0 1 1 0
輸出樣例#1:
6 xoox ___o ___o xoox說明
所有的 10 組數據中 N, M ,以及景點數 K 的范圍規定如下
輸入文件中的所有整數均不小于 0 且不超過 2^16
感謝@panda_2134 提供Special Judge
?
Solution
顯然的最小斯坦納樹問題,? 表示以這個格子為根,關鍵點選取狀態為的最小個數。
#include<bits/stdc++.h> using namespace std; const int MAXN=12; const int MAXS=2005; const int dx[4]={0,0,-1,1}; const int dy[4]={1,-1,0,0}; const int INF=0x3f3f3f3f; int n,m,cnt,xt,yt; int f[MAXN][MAXN][MAXS],c[MAXN][MAXN],p[MAXN][MAXN]; struct node{int x,y,s; } pre[MAXN][MAXN][MAXS]; bool ans[MAXN][MAXN],vis[MAXN][MAXN][MAXS]; queue<node> Q; inline int read() {int f=1,x=0; char c=getchar();while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }return x*f; } void find(int x,int y,int s) {ans[x][y]=1;node q=pre[x][y][s];if (q.x==0) return;find(q.x,q.y,q.s);if (q.x==x&&q.y==y) find(x,y,(s-q.s)|p[x][y]); } void spfa() {while (!Q.empty()){node q=Q.front(); Q.pop();int x=q.x,y=q.y,s=q.s;vis[x][y][s]=0;for (int i=0;i<4;i++){int xx=x+dx[i],yy=y+dy[i],ss=s|p[xx][yy];if (xx<1||xx>n||yy<1||yy>m) continue;if (f[x][y][s]+c[xx][yy]<f[xx][yy][ss]) {f[xx][yy][ss]=f[x][y][s]+c[xx][yy];pre[xx][yy][ss]=(node){x,y,s};if (s==ss&&(!vis[xx][yy][ss])) vis[xx][yy][ss]=1,Q.push((node){xx,yy,ss});}}} } int main() {n=read(),m=read(),cnt=0;memset(f,INF,sizeof f);for (int i=1;i<=n;i++)for (int j=1;j<=m;j++){c[i][j]=read();if (!c[i][j]) p[i][j]=(1<<(cnt++)),xt=i,yt=j,f[i][j][p[i][j]]=0; }for (int S=1;S<(1<<cnt);S++){for (int i=1;i<=n;i++)for (int j=1;j<=m;j++)if ((S&p[i][j]) || !p[i][j]){for (int s=(S-1)&S;s;s=(s-1)&S){int t=f[i][j][ (S-s)|p[i][j] ]+f[i][j][ s|p[i][j] ]-c[i][j]; //(i,j)這一點重復計算了,把c[i][j]消去。 if (f[i][j][S]>t) f[i][j][S]=t,pre[i][j][S]=(node){i,j,s|p[i][j]};//更新f[i][j][S],并記錄路徑。 }if (f[i][j][S]<INF) vis[i][j][S]=1,Q.push((node){i,j,S}); }spfa();}printf("%d\n",f[xt][yt][(1<<cnt)-1]);find(xt,yt,(1<<cnt)-1);for (int i=1;i<=n;i++){for (int j=1;j<=m;j++)if (p[i][j]) putchar('x');else if (ans[i][j]) putchar('o');else putchar('_');puts("");}return 0; }?
4.一些斯坦納樹題
[THUSC2017]巧克力 斯坦納樹+隨機+二分
[BZOJ 4006] 管道連接
[hdu 3331]Trip the Lights Fantastic
[HDU 4085] Peach Blossom Spring
[ZOJ 3613] Wormhole Transport
?
5.萌新的總結
用狀壓解決最小斯坦納樹的時間復雜度對于是指數級別的,所以一般的最小斯坦納數問題中,的范圍在左右。
斯坦納樹實現并不難,思維難度也不高,還是一個很實用的算法。
總結
以上是生活随笔為你收集整理的业界萌新对斯坦纳树的小结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 木瓜茶的功效与作用、禁忌和食用方法
- 下一篇: DNF如何进入远古地下城与异界地下城