poj1639 Picnic Planning 限制顶点度数的MST
来源:互联网 发布:爱言叶 动作数据 编辑:程序博客网 时间:2024/06/10 03:23
题意:
有n个兄弟去野餐,目的地为Park。每个人可以选择直接去Park,也可以选择去其他人家,和他一起坐车去Park。
每个人家的停车位没有限制,但是Park的停车数不能超过k。问所有人的最短路程。
思路:
假设Park的停车数没有限制,那么这题就是一道最小生成树了。
但是本题限制Park的停车数不能超过k,把Park看做根节点记为V0,那么就是说它的度数不能超过k。
得到一棵k度限制生成树的步骤:
1. 忽略根节点做一次kruskal,此时得到的是一个森林,包含了m个最小生成树。
2. 对于每一颗最小生成树树,选择其中离根节点最近的点,向根节点连一条边,此时得到了一棵m度的最小生成树。
3. 由m度生成树得到m+1度生成树:
(1). 用dp预处理出当前生成树中从V0到点i的路径上与V0无关联的权值最大的边,记为dp[i].d,该边的两端点记为dp[i].u和dp[i].v。
(2). 对于一个不在生成树中的边<V0, v>, 如果将该边加入生成树中,则一定会得到一个环。
此时我们删掉环中权值最大的边,即(1)中预处理得到的dp[v],得到一棵m+1度的生成树。
(3). 对于(2)枚举每一个v,记minnum=min{(V0, v) - dist[v].d },使minnum得到最小值的点v就是这次选择的点。连接V0, v,删去dp[v]。
4. 重复步骤3直到得到一棵k度限制生成树。本题要求度数不超过k,所以在某一步中,minnum>=0,就可以输出答案了。
关于minnum的含义:
minnum为在从m度生成树得到m+1度生成树的过程中,选择一个点v(连接V0, v,删去dp[v])可以得到的最大利益,即生成树的值最多可以减少多少。
minnum为负数,表示选择点v可以生成树的值减少,那么使minnum最小的点就是可以使生成树的值减少最多的点,这次我们便选择它。
如果minnum>=0,说明得到m+1度生成树不会获得任何利益,就不用继续下去,直接输出答案即可。
关于最小度数限制生成树详情参考2004国家集训队汪汀的论文。
代码(760K,47MS):
#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>#include <vector>#include <map>#include <string>#define INF 0x3f3f3f3f#define MAXN 22using namespace std;struct Edge{int u, v, d;Edge() {}Edge(int a, int b, int c) : u(a), v(b), d(c) {}bool operator < (const Edge &e) const {return d < e.d;}};int n, m, k;int cnt;int ans;int parent[MAXN]; // 并查集map<string, int> nodes;vector<Edge> edges;Edge dp[MAXN];int g[MAXN][MAXN];bool tree[MAXN][MAXN]; // tree[i][j]=true表示<i, j>这条边在最小生成树中int minEdge[MAXN];int find(int p) {if (p == parent[p]) return parent[p];return parent[p] = find(parent[p]);}void un(int p, int q) {parent[find(p)] = find(q);}void kruskal() {sort(edges.begin(), edges.end());for (int i = 0; i < edges.size(); i++) {int p = edges[i].u;int q = edges[i].v;if (p == 1 || q == 1) continue; // 忽略根节点if (find(p) != find(q)) {un(p, q);tree[p][q] = tree[q][p] = 1;ans += edges[i].d;}}}void dfs(int cur, int pre) {for (int i = 2; i <= cnt; i++) {if (i == pre || !tree[cur][i]) continue;if (dp[i].d == -1) {if (dp[cur].d > g[cur][i]) dp[i] = dp[cur];else {dp[i].u = cur;dp[i].v = i;dp[i].d = g[cur][i];}}dfs(i, cur);}}void solve() {int keyPoint[MAXN];for (int i = 2; i <= cnt; i++) {if (g[1][i] != INF) {// 点i在哪颗最小生成树中int color = find(i);// 每颗最小生成树中距离根节点最近的点与根节点的距离if (minEdge[color] > g[1][i]) {minEdge[color] = g[1][i];keyPoint[color] = i;}}}for (int i = 1; i <= cnt; i++) {if (minEdge[i] != INF) {m++;tree[1][keyPoint[i]] = tree[keyPoint[i]][1] = 1;ans += g[1][keyPoint[i]];}}// 由i-1度生成树得i度生成树for (int i = m + 1; i <= k; i++) {memset(dp, -1, sizeof(dp));dp[1].d = -INF;for (int j = 2; j <= cnt; j++)if (tree[1][j]) dp[j].d = -INF;dfs(1, -1); // dp预处理int idx, minnum = INF;for (int j = 2; j <= cnt; j++) {if (minnum > g[1][j] - dp[j].d) {minnum = g[1][j] - dp[j].d;idx = j;}}if (minnum >= 0) break;tree[1][idx] = tree[idx][1] = 1;tree[dp[idx].u][dp[idx].v] = tree[dp[idx].v][dp[idx].u] = 0;ans += minnum;}}void init() {memset(g, 0x3f, sizeof(g));memset(tree, 0, sizeof(tree));memset(minEdge, 0x3f, sizeof(minEdge));m = 0;cnt = 1;ans = 0;nodes["Park"] = 1;for (int i = 0; i < MAXN; i++)parent[i] = i;}int main() {scanf("%d", &n);string s1, s2;int d;init();for (int i = 1; i <= n; i++) {cin >> s1 >> s2 >> d;if (!nodes[s1]) nodes[s1] = ++cnt;if (!nodes[s2]) nodes[s2] = ++cnt;int u = nodes[s1], v = nodes[s2];edges.push_back(Edge(u, v, d));g[u][v] = g[v][u] = min(g[u][v], d);}scanf("%d", &k);kruskal(); // 忽略根节点先计算一次最小生成树,此时得到一个森林solve();printf("Total miles driven: %d\n", ans);return 0;}
- poj1639 Picnic Planning 限制顶点度数的MST
- poj1639 Picnic Planning 最小度数限制生成树
- poj1639 Picnic Planning
- POJ1639 Picnic Planning 最小度限制生成树
- POJ1639 Picnic Planning(度限制生成树)
- poj1639 Picnic Planning,K度限制生成树
- POJ1639-某点度限制的MST
- poj1639——Picnic Planning
- (advanced) UVA 最小生成树(限制度数) UVA 1537 Picnic Planning
- Picnic Planning 最小度限制生成树
- poj 1639 Picnic Planning 单度限制的最小生成树
- POJ 1639 Picnic Planning(有限制的最小生成树)
- POJ 1639 Picnic Planning【度限制最小生成树】
- POJ1638 Picnic Planning (最小限制度生成树)
- POJ 1639:Picnic Planning(最小度限制生成树)
- poj 1639 Picnic Planning(最小度限制生成树)
- POJ 1639 Picnic Planning【度限制最小生成树】
- 【POJ】1639 Picnic Planning 度限制最小生成树
- rhel crontab任务计划调度
- HDU 5135 Little Zu Chongzhi's Triangles(状压dp或者贪心)
- 【Delphi】多线程使用(1)
- 梦想是你的方向,是你的未来
- Struts2常用标签总结
- poj1639 Picnic Planning 限制顶点度数的MST
- set--STL
- nanoPC-T1 4412u-boot启动
- css3 animation动画对应属性解释
- Oracle - 系统权限详细列表
- 【Android 一般进阶】如何退出app
- 计算机毕业课程设计源码打包下载2
- 业内docker技巧和最佳实践的想法
- 未来迷茫