标签:graph ... ref bsp eof prim 类型 \n try
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions:31622 | Accepted: 8670 |
Description
Input
Output
Sample Input
4 0 0 0 0 1 1 1 1 2 1 0 3 0
Sample Output
1.000
Source
题意:
有$n$个城市,每个城市有对应的坐标和海拔。两个城市之间的距离是坐标的距离,路的花费是海拔之差。
现在要建$n-1$条路,使得花费之和比距离之和最小。
思路:
一道0/1分数规划的题目。
0/1分数规划模型指:给定整数$a_1,a_2,...,a_n$,以及$b_1,b_2,...,b_n$,求一组解$x_i(1\leq i \leq n,x_i=0或1)$,
使得$\frac{\sum_{i=1}^{n} a_i*x_i}{\sum_{i=1}^{n}b_i*x_i}$最大化。
这种类型的题目我们可以通过二分答案来做。
因为如果对于$mid$,存在一组解,使得$\sum_{i=1}^{n}(a_i - mid * b_i) * x_i \geq 0$那么我们可以变形得到
存在一组解,使得$\frac{\sum_{i=1}^{n} a_i*x_i}{\sum_{i=1}^{n}b_i*x_i} \geq mid$
也就是说,$mid$比我们实际的答案要小。
反之,如果对于任意一组解,都有$\sum_{i=1}^{n}(a_i - mid * b_i) * x_i <0$那么我们可以得到
任意的解都有$\frac{\sum_{i=1}^{n} a_i*x_i}{\sum_{i=1}^{n}b_i*x_i} < mid$
也就是说,$mid$比我们实际的答案要大。
所以我们每次只需要计算$\sum_{i=1}^{n}(a_i - mid * b_i)*x_i$的最大值,如果最大值非负,令$st = mid$,否则$ed = mid$
对于这道题,也是类似。我们二分最终的答案。
每一次重新建图,城市和城市之间的边变为$cost - mid * length$
然后在新图上跑最小生成树。
如果最小生成树的值非负,说明实际答案比$mid$要大,令$st = mid$
由于这道题是完全图,而点的个数只有$1000$所以用prim比较好
WA了好久,后来发现是对d赋初值的问题。
对于double的数组赋初值$+\infty$不能用$0x3f$而应该用$0x7f$,就改了这里就过了。
1 #include<iostream> 2 //#include<bits/stdc++.h> 3 #include<cstdio> 4 #include<cmath> 5 //#include<cstdlib> 6 #include<cstring> 7 #include<algorithm> 8 //#include<queue> 9 #include<vector> 10 //#include<set> 11 //#include<climits> 12 //#include<map> 13 using namespace std; 14 typedef long long LL; 15 #define N 100010 16 #define pi 3.1415926535 17 #define inf 0x3f3f3f3f 18 19 const int maxn = 1005; 20 const double eps = 1e-7; 21 int n; 22 struct city{ 23 double x, y, height; 24 }c[maxn]; 25 double dist[maxn][maxn], cost[maxn][maxn], g[maxn][maxn]; 26 27 double get_dist(int i, int j) 28 { 29 return sqrt((c[i].x - c[j].x) * (c[i].x - c[j].x) + (c[i].y - c[j].y) * (c[i].y - c[j].y)); 30 } 31 32 33 double d[maxn]; 34 bool vis[maxn]; 35 void prim() 36 { 37 memset(d, 0x7f, sizeof(d)); 38 memset(vis, 0, sizeof(vis)); 39 /*for(int i = 1; i <= n; i++){ 40 d[i] = (double)inf; 41 vis[i] = 0; 42 }*/ 43 d[1] = 0; 44 for(int i = 1; i <= n; i++){ 45 int x = 0; 46 for(int j = 1; j <= n; j++){ 47 if(!vis[j] && (x == 0 || d[j] < d[x]))x = j; 48 } 49 vis[x] = 1; 50 for(int y = 1; y <= n; y++){ 51 if(!vis[y])d[y] = min(d[y], g[x][y]); 52 } 53 } 54 } 55 56 void getgraph(double mid) 57 { 58 for(int i = 1; i <= n; i++){ 59 for(int j = i; j <= n; j++){ 60 g[i][j] = g[j][i] = cost[i][j] - mid * dist[i][j]; 61 } 62 } 63 } 64 65 bool check(double mid) 66 { 67 getgraph(mid); 68 prim(); 69 double res = 0; 70 for(int i = 1; i <= n; i++){ 71 res += d[i]; 72 } 73 return res >= 0; 74 } 75 76 77 int main() 78 { 79 while(scanf("%d", &n) != EOF && n){ 80 for(int i = 1; i <= n; i++){ 81 scanf("%lf%lf%lf", &c[i].x, &c[i].y, &c[i].height); 82 } 83 84 for(int i = 1; i <= n; i++){ 85 for(int j = i; j <= n; j++){ 86 dist[i][j] = dist[j][i] = get_dist(i, j); 87 cost[i][j] = cost[j][i] = fabs(c[i].height - c[j].height); 88 } 89 } 90 double st = 0.0, ed = 100.0; 91 while(ed - st >= eps){ 92 double mid = (st + ed) / 2; 93 if(check(mid))st = mid; 94 else ed = mid; 95 } 96 printf("%.3f\n", ed); 97 } 98 99 return 0; 100 }
poj2728 Desert King【最优比率生成树】【Prim】【0/1分数规划】
标签:graph ... ref bsp eof prim 类型 \n try
原文地址:https://www.cnblogs.com/wyboooo/p/9988567.html