(最大k度限制生成树)POJ 1639 - Picnic Planning

题意:

给一个无向带权图,图上有不超过20个人和1个公园,现在这些人想到公园去集合,他们可以直接去公园也可以,和其他人一起坐车去公园(假设他们的车容量无限),但是这个公园停车场只有k个位置,现在要求他们到达公园所需要的总花费。



分析:

乍一看是最小生成树,但是停车场只有k个位置,所以就限定了公园节点只能最多连k个人,也就是说有一个点的度数是给定了的。

想了很久,第一感觉就是想其他生成树那样,肯定要把边删去,从环中选择更优解, 按套路来说。

但是想了很久不知道怎么处理。

不过,看到题目只有20个人,k<20,可以从n个人中选出k个人,与停车场连接,然后跑最小生成树。虽然很暴力,但最大复杂度才C(20,10)*mlogm,看起来不是很大啊,也的的确确A了,但是跑了接近2s,显然POJ数据真的很水。

其实这题是经典的问题,国家队论文里有讲,据说刘汝佳黑书里也有。推荐一个不错的博客:http://blog.csdn.net/nacl__/article/details/52052133

没错,我就是抄他代码的,自己写半天感觉非常搓,不过,他的代码没有删边,

这句话有问题,我修改了一下。

最近看了一下生成树和最短路的题,感觉天天发现新大陆啊。



代码:

标程

  1 #include <set>
  2 #include <map>
  3 #include <list>
  4 #include <cmath>
  5 #include <queue>
  6 #include <stack>
  7 #include <vector>
  8 #include <bitset>
  9 #include <string>
 10 #include <cctype>
 11 #include <cstdio>
 12 #include <cstring>
 13 #include <cstdlib>
 14 #include <iostream>
 15 #include <algorithm>
 16 // #include <unordered_map>
 17
 18 using namespace std;
 19
 20 typedef long long ll;
 21 typedef unsigned long long ull;
 22 typedef pair<int, int> pii;
 23 typedef pair<ull, ull> puu;
 24
 25 #define inf (0x3f3f3f3f)
 26 #define lnf (0x3f3f3f3f3f3f3f3f)
 27 #define eps (1e-9)
 28 #define fi first
 29 #define se second
 30
 31 bool sgn(double a, string select, double b) {
 32     if(select == "==")return fabs(a - b) < eps;
 33     if(select == "!=")return fabs(a - b) > eps;
 34     if(select == "<")return a - b < -eps;
 35     if(select == "<=")return a - b < eps;
 36     if(select == ">")return a - b > eps;
 37     if(select == ">=")return a - b > -eps;
 38 }
 39
 40
 41 //--------------------------
 42
 43 const ll mod = 1000000007;
 44 const int maxn = 30;
 45
 46 struct Edge {
 47     int u, v, d;
 48     Edge() {}
 49     Edge(int a, int b, int c): u(a), v(b), d(c) {}
 50     bool operator<(const Edge &e)const {
 51         return d < e.d;
 52     }
 53 };
 54
 55 int n, m, k;
 56 int cnt;
 57 int ans;
 58 int parent[maxn];
 59 map<string, int> nodes;
 60 vector<Edge>edges;
 61 int g[maxn][maxn];
 62 bool tree[maxn][maxn];
 63 int minEdge[maxn];
 64 Edge dp[maxn];
 65
 66 int find(int p) {
 67     if(p == parent[p])return p;
 68     else return parent[p] = find(parent[p]);
 69 }
 70
 71 void un(int p, int q) {
 72     parent[find(p)] = find(q);
 73 }
 74
 75 void Kruskal() {
 76     sort(edges.begin(), edges.end());
 77     for(int i = 0; i < edges.size(); i++) {
 78         int p = edges[i].u;
 79         int q = edges[i].v;
 80         if(p == 1 || q == 1)continue;
 81         if(find(p) != find(q)) {
 82             un(p, q);
 83             tree[p][q] = tree[q][p] = 1;
 84             ans += edges[i].d;
 85         }
 86     }
 87 }
 88
 89 void dfs(int cur, int pre) {
 90     for(int i = 2; i <= cnt; i++) {
 91         if(i == pre || !tree[cur][i])continue;
 92         if(dp[i].d == -1) {
 93             if(dp[cur].d > g[cur][i])dp[i] = dp[cur];
 94             else {
 95                 dp[i].u = cur;
 96                 dp[i].v = i;
 97                 dp[i].d = g[cur][i];
 98             }
 99         }
100         dfs(i, cur);
101     }
102 }
103
104
105 void init() {
106     memset(g, inf, sizeof(g));
107     memset(tree, 0, sizeof(tree));
108     memset(minEdge, inf, sizeof(minEdge));
109     m = 0;
110     cnt = 1;
111     ans = 0;
112     nodes["Park"] = 1;
113     for(int i = 0; i < maxn; i++) {
114         parent[i] = i;
115     }
116 }
117
118 void solve() {
119     scanf("%d", &n);
120     string s1, s2;
121     int d;
122     init();
123     for(int i = 1; i <= n; i++) {
124         cin >> s1 >> s2 >> d;
125         if(!nodes[s1])nodes[s1] = ++cnt;
126         if(!nodes[s2])nodes[s2] = ++cnt;
127         int u = nodes[s1];
128         int v = nodes[s2];
129         edges.push_back(Edge(u, v, d));
130         g[u][v] = g[v][u] = min(g[u][v], d);
131     }
132     scanf("%d", &k);
133     Kruskal();
134     int keyPoint[maxn];
135     for(int i = 2; i <= cnt; i++) {
136         if(g[1][i] != inf) {
137             int color = find(i);
138             if(minEdge[color] > g[1][i]) {
139                 minEdge[color] = g[1][i];
140                 keyPoint[color] = i;
141
142             }
143         }
144     }
145     for(int i = 1; i <= cnt; i++) {
146         if(minEdge[i] != inf) {
147             m++;
148             tree[1][keyPoint[i]] = tree[keyPoint[i]][1] = 1;
149             ans += g[1][keyPoint[i]];
150         }
151     }
152     for(int i = m + 1; i <= k; i++) {
153         memset(dp, -1, sizeof(dp));
154         dp[1].d = -inf;
155         for(int j = 2; j <= cnt; j++)
156             if(tree[1][j])
157                 dp[j].d = -inf;
158         dfs(1, -1);
159         int idx, minnum = inf;
160         for(int j = 2; j <= cnt; j++) {
161             if(minnum > g[1][j] - dp[j].d) {
162                 minnum = g[1][j] - dp[j].d;
163                 idx = j;
164             }
165         }
166         if(minnum >= 0)
167             break;
168         tree[1][idx] = tree[idx][1] = 1;
169         tree[dp[idx].u][dp[idx].v] = tree[dp[idx].v][dp[idx].u] = 0;
170         ans += minnum;
171     }
172     printf("Total miles driven: %d\n", ans);
173 }
174
175 int main() {
176
177 #ifndef ONLINE_JUDGE
178     freopen("1.in", "r", stdin);
179     // freopen("1.out", "w", stdout);
180 #endif
181     // iostream::sync_with_stdio(false);
182     solve();
183     return 0;
184 }

暴力

  1 #include <set>
  2 #include <map>
  3 #include <list>
  4 #include <cmath>
  5 #include <queue>
  6 #include <stack>
  7 #include <vector>
  8 #include <bitset>
  9 #include <string>
 10 #include <cctype>
 11 #include <cstdio>
 12 #include <cstring>
 13 #include <cstdlib>
 14 #include <iostream>
 15 #include <algorithm>
 16 // #include <unordered_map>
 17
 18 using namespace std;
 19
 20 typedef long long ll;
 21 typedef unsigned long long ull;
 22 typedef pair<int, int> pii;
 23 typedef pair<ull, ull> puu;
 24
 25 #define inf (0x3f3f3f3f)
 26 #define lnf (0x3f3f3f3f3f3f3f3f)
 27 #define eps (1e-9)
 28 #define fi first
 29 #define se second
 30
 31 bool sgn(double a, string select, double b) {
 32     if(select == "==")return fabs(a - b) < eps;
 33     if(select == "!=")return fabs(a - b) > eps;
 34     if(select == "<")return a - b < -eps;
 35     if(select == "<=")return a - b < eps;
 36     if(select == ">")return a - b > eps;
 37     if(select == ">=")return a - b > -eps;
 38 }
 39
 40
 41 //--------------------------
 42
 43 const ll mod = 1000000007;
 44 const int maxn = 100010;
 45
 46 int n, k;
 47
 48 map<string, int> name;
 49 int cnt;
 50 int edn;
 51 int pkn;
 52
 53 struct Edge {
 54     int u, v, c;
 55 };
 56
 57 bool cmp(Edge a, Edge b ) {
 58     return a.c < b.c;
 59 }
 60
 61
 62 Edge raw_edges[500];
 63 Edge park_edges[500];
 64 Edge edges[500];
 65
 66 string a, b;
 67 int x;
 68
 69 int ans = inf;
 70
 71 int max_park;
 72
 73 int par[500];
 74 int findx(int x) {
 75     if(par[x] == x)return x;
 76     else return par[x] = findx(par[x]);
 77 }
 78
 79
 80 int Kruskal(int n) {
 81     int m = edn + max_park;
 82     for(int i = 0; i < n; i++) {
 83         par[i] = i;
 84     }
 85     sort(edges, edges + m , cmp);
 86     int cnt = 0;
 87     int ans = 0;
 88     for(int i = 0; i < m; i++) {
 89         int u = edges[i].u;
 90         int v = edges[i].v;
 91         int c = edges[i].c;
 92         int t1 = findx(u);
 93         int t2 = findx(v);
 94         if(t1 != t2) {
 95             ans += c;
 96             par[t1] = t2;
 97             cnt++;
 98         }
 99         if(cnt == n - 1)break;
100     }
101     if(cnt < n - 1)return -1;
102     else return ans;
103 }
104
105
106 int select[30];
107
108 void dfs(int now, int pre) {
109     if(now >= max_park) {
110         for(int i = 0; i < edn; i++) {
111             edges[i] = raw_edges[i];
112         }
113         int con = edn;
114         for(int i = 0; i < now; i++) {
115             edges[con++] = park_edges[select[i]];
116         }
117         int mins = Kruskal(cnt);
118         // for(int i = edn; i < con; i++) {
119         //     printf("%d %d\n", edges[i].u, edges[i].v );
120         // }
121         // printf("res = %d\n", mins );
122         if(mins != -1) {
123             ans = min(ans, mins);
124         }
125         return ;
126     }
127     for(int i = pre + 1; i < pkn; i++) {
128         select[now] = i;
129         dfs(now + 1, i);
130     }
131
132 }
133
134
135 void solve() {
136     while(cin >> n) {
137         cnt = edn = pkn = 0;
138         ans = inf;
139         name.clear();
140         for(int i = 0; i < n; i++) {
141             cin >> a >> b >> x;
142             if(name.find(a) == name.end()) {
143                 name[a] = cnt++;
144             }
145             if(name.find(b) == name.end()) {
146                 name[b] = cnt++;
147             }
148             if(a == "Park" || b == "Park") {
149                 park_edges[pkn++] = Edge{name[a], name[b], x};
150             } else {
151                 raw_edges[edn++] = Edge{name[a], name[b], x};
152             }
153         }
154         scanf("%d", &k);
155         max_park = min(pkn, k);
156         dfs(0, -1);
157         printf("Total miles driven: %d\n", ans);
158     }
159
160
161 }
162
163 int main() {
164
165 #ifndef ONLINE_JUDGE
166     freopen("1.in", "r", stdin);
167     freopen("1.out", "w", stdout);
168 #endif
169     // iostream::sync_with_stdio(false);
170     solve();
171     return 0;
172 }
时间: 2024-12-20 00:09:04

(最大k度限制生成树)POJ 1639 - Picnic Planning的相关文章

POJ 1639 Picnic Planning(初遇最小度限制生成树)

这是最小度限制生成树的经典问题,题意就不说了 题目链接:http://poj.org/problem?id=1639 一般都是1个顶点的度有限制k,如果每个顶点的度都有限制,那么当前是NP难的. 为了解决这个题目,先把限制度数的点设为V0点,那么把这一点先除外,那么剩下的点都没有度数限制,所有先对他们进行分析,把他们求生成森林后,假设得到t个连通分量,所以为了生成一棵把v0包含在内的树,必须让v0的度数限制度数k>=t,如果<t,无解. 接下来k度中已经用掉了t度,如何求从t度到k度的最小生成

K度限制MST poj 1639

/* k度限制MST:有一个点的度<=k的MST poj 1639 要求1号点的度不超过k 求MST 我们先把1号点扔掉 跑MST 假设有sum个连通分支 然后把这sum个分支连到1上 就得到了一个sum度的MST 这里往上连的时候 我们连这个分支里 距离1最近的 然后我们在1上加一条边 (即加一个度)得到sum+1度的MST 这里加边的时候 1连出去的每一条边都试一遍 取最小 假设当前1连到了 i 因为原来是个树 这样一搞就形成一个环 我们现在要删去环里面最长边 来得到更小的ans 我么维护d

poj 1639 Picnic Planning 度限制mst

https://vjudge.net/problem/POJ-1639 题意: 有一群人,他们要去某一个地方,每个车可以装无数个人,给出了n条路,包含的信息有路连接的地方,以及路的长度,路是双向的,但是终点只有一个,并且终点能停的车的数量是有限制的,问最少走的路是多少. 思路: 因为终点的停车的数量是有限制的,所以终点的度是有限制的,又因为这题可以用最小生成树解决,所以就是度限制最小生成树. 度限制最小生成树求解思想并不复杂,首先我们把有度限制的点给忽略,然后给每一个连通分量求最小生成树,最后把

【POJ 1639】 Picnic Planning (最小k度限制生成树)

[题意] 有n个巨人要去Park聚会.巨人A和先到巨人B那里去,然后和巨人B一起去Park.B君是个土豪,他家的停车场很大,可以停很多车,但是Park的停车场是比较小.只能停k辆车.现在问你在这个限制条件下.巨人到达Park的最短距离. 如果把那个条件去掉.那么就是就是求最小生成树.加上那个条件其实就是求顶点度数限制为k的最小生成树. Input Input will consist of one problem instance. The first line will contain a s

最小k度限制生成树

[题目描述] 给你一个图,n个点,m条边,求一颗生成树满足如下条件: (1)结点1的度不超过k. (2)在(1)条件下所求生成树最小. [算法引入] 最小k度限制生成树,就是指有特殊的某一点的度不能超过k时的最小生成树. 如果T是G的一个生成树且dT(v0)=k,则称T为G的k度限制生成树. G中权值和最小的k度限制生成树称为G的最小k度生成树. [算法思想] 设特殊的那点为v0,先把v0删除,求出剩下连通图的所有最小生成树. 假如有m棵最小生成树,那么这些生成树必定要跟v0点相连. 也就是说这

poj1639 Picnic Planning,K度限制生成树

题意: 矮人虽小却喜欢乘坐巨大的轿车,车大到可以装下无论多少矮人.某天,N(N≤20)个矮人打算到野外聚餐.为了集中到聚餐地点,矮人A 要么开车到矮人B 家中,留下自己的轿车在矮人B 家,然后乘坐B 的轿车同行:要么直接开车到聚餐地点,并将车停放在聚餐地.虽然矮人的家很大,可以停放无数量轿车,但是聚餐地点却最多只能停放K 辆轿车.给你一张加权无向图,描述了N 个矮人的家和聚餐地点,求出所有矮人开车最短总路程. 单点K度限制最小生成树 算法步骤: 1.求出除去K度点的最小生成森林,设森林数为m 2

poj1639,uva1537,uvalive2099,scu1622,fzu1761 Picnic Planning (最小限制生成树)

Picnic Planning Time Limit: 5000MS   Memory Limit: 10000K Total Submissions: 10742   Accepted: 3885 Description The Contortion Brothers are a famous set of circus clowns, known worldwide for their incredible ability to cram an unlimited number of the

poj1639 Picnic Planning 最小度数限制生成树

题意:若干个人开车要去park聚会,但是park能停的车是有限的,为k.所以这些人要通过先开车到其他人家中,停车,然后拼车去聚会.另外,车的容量是无限的,他们家停车位也是无限的.求开车总行程最短. 就是求一最小生成树,但是对于其中一个点其度不能超过k. 思路: 1. 将park点取出 将剩下的点求出最小生成树  出现i个联通块 2. 再每个块中选择与park点相邻的最小边 到此park点已经连了i条边 park点最大可以连接k个点 得到Sum值 3. 需要求出i+1-->k 条的Sum值 每次添

K - The Unique MST - poj 1679

题目的意思已经说明了一切,次小生成树... ************************************************************************************ #include<algorithm>#include<stdio.h>#include<string.h>#include<queue>using namespace std; const int maxn = 105;const int oo