【题意】:求最小比率生成树。
【题解】:最小比率生成树和01分数规划都是从这里学到的。
最小比率生成树的模型其实就是01分数规划,关于01分数规划的资料,网上一大堆。
简单说下做法,就是构造一个01分数规划的式子,然后变形,利用MST求取当前的最小值。
然后利用二分或者Dinkelbach逼近到最优解即为答案。
【代码】:
1 #include "iostream"
2 #include "cstdio"
3 #include "cstring"
4 #include "algorithm"
5 #include "vector"
6 #include "queue"
7 #include "cmath"
8 #include "string"
9 #include "cctype"
10 #include "map"
11 #include "iomanip"
12 using namespace std;
13 #define pb push_back
14 #define lc(x) (x << 1)
15 #define rc(x) (x << 1 | 1)
16 #define lowbit(x) (x & (-x))
17 #define ll long long
18 #define maxn 1050
19 #define eps 1e-6
20
21 int n;
22 double d[maxn][maxn];
23 int cost[maxn][maxn];
24
25 struct Point {
26 double x, y;
27 int z;
28 }p[maxn];
29
30 double getdist(Point &a, Point &b) {
31 return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
32 }
33
34 int getcost(Point &a, Point &b) {
35 return abs(a.z - b.z);
36 }
37
38 double prim(int s, double &l) {
39 double anslen = 0.0, anscost = 0.0;
40 bool visit[maxn];
41 double dist[maxn], tmp, ans = 0.0;
42 int pre[maxn];
43 for(int i = 0; i < n; i++) visit[i] = false, dist[i] = 1e30;
44 dist[s] = 0.0, pre[s] = s;
45 while(1) {
46 int u = -1;
47 for(int i = 0; i < n; i++) {
48 if(!visit[i] && (u == -1 || dist[i] < dist[u])) u = i;
49 }
50 if(u == -1) break;
51 anscost += cost[pre[u]][u];
52 anslen += d[pre[u]][u];
53 ans += dist[u];
54 visit[u] = true;
55 for(int i = 0; i < n; i++) {
56 if(!visit[i] && (tmp = 1.0 * cost[u][i] - l * d[u][i]) < dist[i])
57 dist[i] = tmp, pre[i] = u;
58 }
59 }
60 l = anscost / anslen;
61 return ans;
62 }
63
64 void solve() {
65 double ans= 0.0, tmp = 0.0;
66 while(1) {
67 double tmp = prim(0, ans);
68 if(fabs(tmp) < eps) break;
69 }
70 printf("%.3f\n", ans);
71 }
72
73 int main() {
74 while(scanf("%d", &n) && n) {
75 for(int i = 0; i < n; i++) {
76 scanf("%lf%lf%d", &p[i].x, &p[i].y, &p[i].z);
77 for(int j = 0; j < i; j++) {
78 d[i][j] = d[j][i] = getdist(p[i], p[j]);
79 cost[i][j] = cost[j][i] = getcost(p[i], p[j]);
80 }
81 }
82 solve();
83 }
84 return 0;
85 }
86