POJ 2728 二分+最小生成树
题意:给n个点,可以将每个点的x,y的欧几里得距离(就是坐标系里两点距离公式)看作距离,z的差值即为费用差,求的是所有最小生成树中的min(边费用和/边距离和)。
思路:其实挑战P143有类似的列题,用的是二分枚举答案的方法,只不过不是树。这一题仅仅需要将题给图找出最小生成树,然后同样枚举即可。
虽然网上有许多高级的名词什么最优比率xxx之类的。。以及迭代的方法,不过我认为用二分也很好,易于想到也可以加深理解。
1 #include <iostream> 2 3 #include <string> 4 5 #include <cstdio> 6 7 #include <cstring> 8 9 #include <cstdlib> 10 11 #include <algorithm> 12 13 #include <cmath> 14 15 #define MAXN 1005 16 17 #define INF 1000000000 18 19 #define eps 1e-7 20 21 using namespace std; 22 23 int n; 24 25 double Edge[MAXN][MAXN], lowcost[MAXN]; 26 27 int nearvex[MAXN]; 28 29 struct Point 30 31 { 32 33 int x, y, z; 34 35 }p[MAXN]; 36 37 double cal(int a, int b) 38 39 { 40 41 return sqrt(1.0 * (p[a].x - p[b].x) * (p[a].x - p[b].x) + 1.0 * (p[a].y - p[b].y) * (p[a].y - p[b].y)); 42 43 } 44 45 double prim(int src, double l) 46 47 { 48 49 double cost = 0, len = 0; 50 51 double sum = 0; 52 53 for(int i = 1; i <= n; i++) 54 55 { 56 57 nearvex[i] = src; 58 59 lowcost[i] = abs(p[src].z - p[i].z) - Edge[src][i] * l; 60 61 } 62 63 nearvex[src] = -1; 64 65 for(int i = 1; i < n; i++) 66 67 { 68 69 double mi = INF; 70 71 int v = -1; 72 73 for(int j = 1; j <= n; j++) 74 75 if(nearvex[j] != -1 && lowcost[j] < mi) 76 77 { 78 79 v = j; 80 81 mi = lowcost[j]; 82 83 } 84 85 if(v != -1) 86 87 { 88 89 cost += abs(p[nearvex[v]].z - p[v].z); 90 91 len += Edge[nearvex[v]][v]; 92 93 nearvex[v] = -1; 94 95 sum += lowcost[v]; 96 97 for(int j = 1; j <= n; j++) 98 99 { 100 101 double tmp = abs(p[v].z - p[j].z) - Edge[v][j] * l; 102 103 if(nearvex[j] != -1 && tmp < lowcost[j]) 104 105 { 106 107 lowcost[j] = tmp; 108 109 nearvex[j] = v; 110 111 } 112 113 } 114 115 } 116 117 } 118 119 return sum; 120 121 } 122 123 int main() 124 125 { 126 127 while(scanf("%d", &n) != EOF && n) 128 129 { 130 131 for(int i = 1; i <= n; i++) 132 133 scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].z); 134 135 for(int i = 1; i <= n; i++) 136 137 for(int j = 1; j <= n; j++) 138 139 Edge[i][j] = cal(i, j); 140 141 double low = 0, high = 10.0; //其实二分20多次已经很足够了 142 143 double l = 0.0, r = 100.0, mid; 144 145 while(r - l > eps) 146 147 { 148 149 mid = (l + r) / 2; 150 151 if(prim(1, mid) >= 0) l = mid; 152 153 else r = mid; 154 155 } 156 157 printf("%.3f\n", r); 158 159 } 160 161 return 0; 162 163 }
适当比较,砥砺前行