POJ_2728
最优比率生成树问题,黑书上有详细的介绍,在求的时候可以直接二分K,也可以先假定一个K然后求得一个新的K,如此反复迭代下去。
对于这个题而言,如果直接二分的话,大概二分50次就可以保证精度了,而迭代的话大概10次就可以保证精度了,所以迭代的效率还是高一些。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #define MAXD 1010 #define INF 0x3f3f3f3f using namespace std; int N, vis[MAXD]; double dis[MAXD], x[MAXD], y[MAXD], z[MAXD], bet[MAXD][MAXD]; double sqr(double x) { return x * x; } void init() { int i, j; for(i = 0; i < N; i ++) scanf("%lf%lf%lf", &x[i], &y[i], &z[i]); for(i = 0; i < N; i ++) for(j = i + 1; j < N; j ++) bet[i][j] = bet[j][i] = sqrt(sqr(x[i] - x[j]) + sqr(y[i] - y[j])); } double prim(double K) { int i, j, k; double m, ans = 0, t; memset(vis, 0, sizeof(vis)); fill(dis, dis + N, INF); dis[0] = 0; for(i = 0; i < N; i ++) { m = INF; for(j = 0; j < N; j ++) if(!vis[j] && dis[j] < m) m = dis[k = j]; vis[k] = 1; ans += dis[k]; for(j = 0; j < N; j ++) if(!vis[j] && (t = fabs(z[k] - z[j]) - K * bet[k][j]) < dis[j]) dis[j] = t; } return ans; } void solve() { int i; double min = 0, max = INF, mid, ans; for(i = 0; i < 50; i ++) { mid = (min + max) / 2; ans = prim(mid); if(ans < 0) max = mid; else min = mid; } printf("%.3f\n", mid); } int main() { for(;;) { scanf("%d", &N); if(!N) break; init(); solve(); } return 0; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #define MAXD 1010 #define INF 0x3f3f3f3f using namespace std; int N, vis[MAXD], pre[MAXD]; double dis[MAXD], x[MAXD], y[MAXD], z[MAXD], bet[MAXD][MAXD]; double sqr(double x) { return x * x; } void init() { int i, j; for(i = 0; i < N; i ++) scanf("%lf%lf%lf", &x[i], &y[i], &z[i]); for(i = 0; i < N; i ++) for(j = i; j < N; j ++) bet[i][j] = bet[j][i] = sqrt(sqr(x[i] - x[j]) + sqr(y[i] - y[j])); } double prim(double K) { int i, j, k; double m, zt = 0, lt = 0, t; memset(vis, 0, sizeof(vis)); fill(dis, dis + N, INF); dis[0] = 0, pre[0] = 0; for(i = 0; i < N; i ++) { m = INF; for(j = 0; j < N; j ++) if(!vis[j] && dis[j] < m) m = dis[k = j]; vis[k] = 1; lt += bet[pre[k]][k], zt += fabs(z[pre[k]] - z[k]); for(j = 0; j < N; j ++) if(!vis[j] && (t = fabs(z[k] - z[j]) - K * bet[k][j]) < dis[j]) dis[j] = t, pre[j] = k; } return zt / lt; } void solve() { int i; double ans = 0; for(i = 0; i < 10; i ++) ans = prim(ans); printf("%.3f\n", ans); } int main() { for(;;) { scanf("%d", &N); if(!N) break; init(); solve(); } return 0; }