POJ 1639 Picnic Planning (k度限制最小生成树)
2014-09-21 22:33
393 查看
题目类型 k度限制最小生成树
题目意思
给出若干个点若干条边 其中某个点的度数限制最多为某个数 问此条件下原图的最小生成树是多少
解题方法
就是k度限制最小生成树的模型 参考 最小生成树问题的拓展
假设有限制的点为 x
1.把点x和与x关联的边去掉 然后原图剩下 y 个连通分量 求出这y个连通分量各自的最小生成树 然后每个连通分量用一条
权值最小的边与x连起来 (这条边当然是这个连通分量内的点与x的边中权值最小的边) 这样就得出了 限制 y 度最小生成树 当然如果 k < y 则肯定
不存在k度限制生成树
2.第1步求出了 y 度限制最小生成树 那么很容易就可以得出 y + 1 度限制最小生成树 方法是找一条与 x 相连的边假设是 (x, z) 那么如果在上一棵
生成树上加入这条边的话显然会形成一个环 如果要消掉这个环就要删除一条边 那么删除上一棵最小生成树上(x,z)这条路径上权值最大的边就是
最优的方法 (这里可以用一个dp数组保存点 x 到其他点的路径上权值最大的边, 转移方程是对于边 (u, v) dp[v] = max(dp[u], w[u][v]) )
那么加入边(x,z)后生成树的代价就变成 C = 原代价+w(x,z)-dp[z], 可以枚举所有的与x相连的边取 C 最小的方案, 然后把相应边加到生成树中再把应该要 删除的边删掉 然后再计算出一个新的 dp 数组 这样就得出了 y + 1度限制最小生成树 一直重复 k - y次即可 (如果过程中算出的最小的C比原来 生成树的代价还要大则直接结束)
参考代码 - 有疑问的地方在下方留言 看到会尽快回复的
很暴力的代码
题目意思
给出若干个点若干条边 其中某个点的度数限制最多为某个数 问此条件下原图的最小生成树是多少
解题方法
就是k度限制最小生成树的模型 参考 最小生成树问题的拓展
假设有限制的点为 x
1.把点x和与x关联的边去掉 然后原图剩下 y 个连通分量 求出这y个连通分量各自的最小生成树 然后每个连通分量用一条
权值最小的边与x连起来 (这条边当然是这个连通分量内的点与x的边中权值最小的边) 这样就得出了 限制 y 度最小生成树 当然如果 k < y 则肯定
不存在k度限制生成树
2.第1步求出了 y 度限制最小生成树 那么很容易就可以得出 y + 1 度限制最小生成树 方法是找一条与 x 相连的边假设是 (x, z) 那么如果在上一棵
生成树上加入这条边的话显然会形成一个环 如果要消掉这个环就要删除一条边 那么删除上一棵最小生成树上(x,z)这条路径上权值最大的边就是
最优的方法 (这里可以用一个dp数组保存点 x 到其他点的路径上权值最大的边, 转移方程是对于边 (u, v) dp[v] = max(dp[u], w[u][v]) )
那么加入边(x,z)后生成树的代价就变成 C = 原代价+w(x,z)-dp[z], 可以枚举所有的与x相连的边取 C 最小的方案, 然后把相应边加到生成树中再把应该要 删除的边删掉 然后再计算出一个新的 dp 数组 这样就得出了 y + 1度限制最小生成树 一直重复 k - y次即可 (如果过程中算出的最小的C比原来 生成树的代价还要大则直接结束)
参考代码 - 有疑问的地方在下方留言 看到会尽快回复的
很暴力的代码
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <map> #include <vector> #include <algorithm> using namespace std; const int maxn = 1000 + 10; const int INF = 1<<29; vector<int>E[maxn], W[maxn]; vector<int>cc[maxn]; int g[maxn][maxn], g2[maxn][maxn]; bool vis[maxn]; bool used[maxn]; int park, ncc, Nc[maxn]; int S[maxn]; struct Edge { int u, v, w; bool operator < (const Edge & rhs) const { return w < rhs.w; } }; struct DP { int nmax, u, v; }dp[100][1000]; int fa[maxn], np; void get_cc(int u) { // 找连通分量 vis[u] = true; cc[ncc].push_back(u); Nc[u] = ncc; for( int i=0; i<E[u].size(); i++ ) { int v = E[u][i]; if(v == park) continue; if(vis[v]) continue; get_cc(v); } } int find(int x) { return x == fa[x] ? x : find(fa[x]); } int kruscal(int x) { // 求某个连通分量的最小生成树 int no[maxn]; Edge e[maxn]; int ne = 0; for( int i=0; i<cc[x].size(); i++ ) fa[i] = i; for( int i=0; i<cc[x].size(); i++ ) { fa[i] = i, no[i] = cc[x][i]; for( int j=i+1; j<cc[x].size(); j++ ) { int u = cc[x][i], v = cc[x][j]; int w = g[u][v]; if(g[u][v] == -1) continue; e[ne].u = i, e[ne].v = j, e[ne].w = w; ne++; } } sort(e, e+ne); int sum = 0; int tn = cc[x].size(); for( int i=0; i<ne; i++ ) { int u = e[i].u, v = e[i].v, w = e[i].w; int xx = find(u), y = find(v); if(xx != y) { fa[xx] = y; g2[cc[x][u]][cc[x][v]] = g2[cc[x][v]][cc[x][u]] = w; //printf("g2[%d][%d] = %d\n", cc[x][u], cc[x][v], g2[cc[x][u]][cc[x][v]]); sum += w; tn--; if(tn == 1) break; } } //printf("sum =%d\n", sum); return sum; } void find_dp(int u, int fa, int nx) { // 求出那个 dp 数组 vis[u] = true; for( int i=1; i<np; i++ ) { if(g2[u][i] == -1) continue; int v = i; if(v == fa) continue; if(vis[v]) continue; if(dp[nx][u].nmax > g2[u][v]) { dp[nx][v].nmax = dp[nx][u].nmax; dp[nx][v].u = dp[nx][u].u; dp[nx][v].v = dp[nx][u].v; } else { dp[nx][v].nmax = g2[u][v]; dp[nx][v].u = u; dp[nx][v].v = v; } find_dp(v, u, nx); } } void getEdge(int m) { // 根据输入的信息建图 map<string,int>M; memset(g, -1, sizeof(g)); char lname[100], rname[100]; for( int i=0; i<=1000; i++ ) E[i].clear(), W[i].clear(), cc[i].clear(); for( int i=0; i<m; i++ ) { int u, v, w; scanf("%s%s%d", lname, rname, &w); string s = lname; if(M[s] == 0) { u = np; M[s] = np++; } else u = M[s]; s = rname; if(M[s] == 0) { v = np; M[s] = np++; } else v = M[s]; if(strcmp(lname, "Park") == 0) park = u; else if(strcmp(rname, "Park") == 0) park = v; E[u].push_back(v); W[u].push_back(w); E[v].push_back(u); W[v].push_back(w); g[u][v] = g[v][u] = w; //printf("u = %d v = %d w = %d\n", u, v, w); } } int main() { freopen("in", "r", stdin); int m; while(scanf("%d", &m) != EOF) { np = 1; getEdge(m); int k; scanf("%d", &k); ncc = 0; memset(vis, 0, sizeof(vis)); for( int i=1; i<np; i++ ) { if(i == park) continue; if(vis[i]) continue; get_cc(i); ncc++; } int sum = 0; memset(used, 0, sizeof(used)); memset(dp, 0, sizeof(dp)); memset(g2, -1, sizeof(g2)); for( int i=0; i<ncc; i++ ) { sum += kruscal(i); int nmin = INF, mark; for( int j=0; j<cc[i].size(); j++ ) { int u = cc[i][j]; if(g[u][park] == -1) continue; if(nmin > g[u][park]) { nmin = g[u][park]; mark = u; } } dp[i][mark].nmax = 0; memset(vis, 0, sizeof(vis)); find_dp(mark, -1, i); S[i] = mark; used[mark] = true; sum += nmin; } k -= ncc; while(k--) { int nmin = INF, mark, mu, mv; for( int i=0; i<E[park].size(); i++ ) { int v = E[park][i]; if(used[v]) continue; int tmp = g[park][v] - dp[Nc[v]][v].nmax; if(tmp < nmin) { nmin = tmp; mark = v; mu = dp[Nc[v]][v].u, mv = dp[Nc[v]][v].v; } } if(nmin >= 0) break; sum += nmin; used[mark] = true; g2[mu][mv] = 0; //for( int i=2; i<=8; i++ ) printf("%d ", dp[0][i].nmax); memset(dp, 0, sizeof(dp)); for( int i=0; i<ncc; i++ ) { memset(vis, 0, sizeof(vis)); find_dp(S[i], -1, i); } } printf("Total miles driven: %d\n", sum); } return 0; }
相关文章推荐
- POJ-1639 Picnic Planning (最小度限制生成树)(模板题)
- 【POJ 1639】 Picnic Planning (最小k度限制生成树)
- poj1639 Picnic Planning 最小度数限制生成树
- POJ 1639 Picnic Planning(最小度限制生成树)
- [最小k度限制生成树] POJ 1639 Picnic Planning
- POJ 1639:Picnic Planning(最小度限制生成树)
- poj1639 Picnic Planning 最小度数限制生成树
- poj 1639 Picnic Planning 最小K度限制生成树
- POJ 1639 Picnic Planning(初遇最小度限制生成树)
- poj1639 Picnic Planning 最小度数限制生成树
- poj 1639 Picnic Planning(最小K度限制生成树)
- POJ1639 Picnic Planning —— 根节点度数有限制的最小生成树
- POJ 1639 度限制最小生成树Prim
- poj_1639 Picnic Planning(度限制最小生成树)
- pku 1639 Picnic Planning 最小度限制生成树
- POJ 1639 最小度限制生成树
- POJ 1639 Picnic Planning 【最小度限制生成树】
- POJ --- 1639 【k度限制最小生成树】
- poj1639 Picnic Planning,K度限制生成树
- 【POJ】1639 Picnic Planning 度限制最小生成树