浅析SteinerTree(斯坦纳树)
来源:互联网 发布:雀神作弊软件 编辑:程序博客网 时间:2024/04/30 12:46
前几天看ZOJ的一场Monthly,里面有一道和SteinerTree很相近的一道题,之后敲了一下,顺便把SteinerTree整理一下。
首先由我们知道的东西引入:
一个图的最小生成树即这个图上所有点(设集合为G)生成的边权值和最小的树,我们可以知道这个树上任意两点是可到达的,这个可以用prime或者kruskal实现。下面,假如我们只要求G的一个真子集里面的所有点连通,那么我们发现一些边权是没有用的、可以去掉,这样,将指定点集合中的所有点连通,且总边权值和最小的生成树称谓MinimalSteinerTree(最小斯坦纳树),可以看出,最小生成树是最小斯坦纳树的一种特殊情况。
SteinerTree是组合优化学的著名问题,而且是离散数学中几个NP问题之一,可是很多离散书中提都不提.....SteinerTree对于求解数学模型,优化最小网络很有用。
求解方法:
首先,我们从prime的思想出发,如果求最小斯坦纳树,那么只要求对应点集为最小生成树即可,而对应点集的最小生成树和整体最小生成树想比肯定会出现无用点,所以先用floyd算出两点之间最短距离,之后将所有点都两两连接起来,形成一个完全图,这样就将整个图缩了一下,之后,枚举所有可能点集,对每个点集求最小生成树,取最小即可。
可是我们会发现,点集的个数是个不可知,而且每次都要做一次prime算法,所以复杂之高难以估算。
于是,我们要改进一下算,转用DP来求解。
DP转移方程:
dp[mask][i],其中是以i为根,包含mask点集的最小生成树的权值,mask作为点集可以用二进制进行状态压缩。
在得知dp[mask - 1][1...N]的情况下如何退出dp[mask][1...N]呢?
两个步骤实现:
step1:
从点集入手
a = min(dp[m1][i] + dp[m2][i]),其中m1 | m2 = mask。
m1和m2作为mask的子集,且互补。
在计算子集的时候,可有用for(int sub = mask; sum; sum = (sum - 1) & mask)来枚举子集
step2:
从根入手
b = min(dp[mask][j] + dp[j][i])
如果mask点集满足且根为j,那么直接填上[j][i]这条边就行了(前面拿floyd已经缩图了。)
程序中,每次都从dp[mask][1...N]中选出最小的一个dp[mask][c],按这种顺序更新就能保证结果的正确
所以,dp[mask][i] = min(a, b);
附程序(POJ3123的)
#include <iostream>#include <string>#include <map>using namespace std;int main(){int INF = 99999999, N, K, d[30][30], i, j, k, x, y, z;int dp[256][30], e[8], v[30], c, b;string s, t;while (cin >> N >> K && N){map <string, int> cityMap;for (i = 0; i < N; i++)for (j = 0; j < N; j++)d[i][j] = i == j ? 0 : INF;for (i = 0; i < N; i++){cin >> s;cityMap[s] = i;}if (K)while (cin >> s >> t >> z, x = cityMap[s],y = cityMap[t],d[x][y] = d[y][x] = min(d[y][x], z), --K);for (k = 0; k < N; k++)for (i = 0; i < N; i++)for (j = 0; j < N; j++)d[i][j] = min(d[i][j], d[i][k] + d[k][j]);for (i = 0; i < 8; i++){cin >> s;e[i] = cityMap[s];for (j = 0; j < N; j++)dp[1 << i][j] = d[j][e[i]];}for (i = 1; i < 256; i++){if (!(i & (i - 1)))continue;// step1for (k = 0; k < N; k++){dp[i][k] = INF;v[k] = 0;/*for (j = 1; j < i; j++)if ((i | j) == i)dp[i][k] = min(dp[i][k], dp[j][k] + dp[i-j][k]);*/for (int sub = i; sub; sub = (sub - 1) & i){dp[i][k] = min(dp[i][k], dp[sub][k] + dp[i - sub][k]);}}// step2for (j = 0; b = INF, j < N; j++){for (k = 0; k < N; k++)if (dp[i][k] <= b && !v[k])b = dp[i][c = k];for (k = 0, v[c] = 1; k < N; k++)dp[i][c] = min(dp[i][c], dp[i][k] + d[k][c]);}}// step3for (i = 0, b = INF; z = 0, i < 256; b = min(b, z), i++)for (j = 0; y = 0, j < 4; z += !!y * dp[y][x], j++)for (k = 0; k < 8; k += 2)if ((i >> k & 3) == j)y += 3 << k, x = e[k];cout << b << endl;}return 0;}
- 浅析SteinerTree(斯坦纳树)
- hdu 3311 Dig The Wells (SteinerTree斯坦纳树)
- 斯坦纳树(Steiner Tree)
- 斯坦纳树(Steiner Tree)
- bzoj 4774: 修路 (斯坦纳树)
- [BZOJ4774]修路(斯坦纳树+dp)
- csu1965—Message(斯坦纳树)
- CSU 1965(斯坦纳树)
- HYSBZ2595-游览计划(斯坦纳树)
- 斯坦纳树 hdu4085
- 斯坦纳树
- 斯坦纳树
- HDU4085【斯坦纳树】
- 斯坦纳树
- BZOJ4006【斯坦纳树】
- 【模板】斯坦纳树
- 斯坦纳树问题
- 斯坦纳生成树
- 基于”啪啪奇”产品体验谈视频网站移动端发展
- hdu4460(BFS)
- C++ 11 标准
- POJ 1611 The Suspects (并查集)
- vc工程中各种文件的作用
- 浅析SteinerTree(斯坦纳树)
- 国内外软件服务外包平台
- linux-ubuntu下gdb调试技巧
- QT 信号与槽 QT简单加法器的实现
- 理想的营销状态:战略策略战术三位一体
- hibernate中自动创建表的配置
- 直接拿来用!超实用的Java数组技巧攻略
- TopCoder SRM 589 Div2 第3题
- 为什么要学习C语言(转载)