[HDOJ4081]Qin Shi Huang's National Road System

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4081

 

求一个最小生成树,再在这个最小生成树上删一条边,使得这条边两侧的人口数和与边长比值最大。用kruskal怎么写都写不出来,后来查了题解,prim会好一些:

求出最小生成树的同时记录最小生成树中任意两个点之间唯一路径的最大权的边的值,这个只要在要更新树的时候,在已经生成的树中更新就行了

AC代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <set>
 6 #include <queue>
 7 #include <map>
 8 #include <cmath>
 9 #include <vector>
10 using namespace std;
11 #define N 1010
12 #define pi acos(-1.0)
13 #define inf 100000000
14 #define eps 1e-9
15 typedef long long ll;
16 typedef unsigned long long ull;
17 struct point{
18     int x,y,v;
19 }p[N];
20 double a[N][N],maxx[N][N],dis[N];
21 int n,pre[N];
22 bool vis[N];
23 void prim(){
24     double ans=0;
25     memset(vis,false,sizeof(vis));
26     memset(maxx,0,sizeof(maxx));
27     for(int i=1;i<=n;i++){
28         dis[i]=a[1][i];
29         pre[i]=1;
30     }
31     dis[1]=0;
32     vis[1]=true;
33     for(int i=1;i<n;i++){
34         int k=0;
35         double tmp=inf;
36         for(int j=1;j<=n;j++){
37             if(!vis[j]&&dis[j]<tmp){
38                 k=j;
39                 tmp=dis[j];
40             }
41         }
42         vis[k]=true;
43         ans+=tmp;
44         for(int j=1;j<=n;j++){
45             if(!vis[j]&&dis[j]>a[k][j]){
46                 dis[j]=a[k][j];
47                 pre[j]=k;
48             }
49         }
50         for(int j=1;j<=n;j++){
51             if(vis[j]&&j!=k){
52                 maxx[j][k]=max(maxx[j][pre[k]],tmp);
53                 maxx[k][j]=maxx[j][k];
54             }
55         }
56     }
57     double an=0;
58     for(int i=1;i<=n;i++){
59         for(int j=1;j<=n;j++){
60             if(i!=j){
61                 an=max(an,double(p[i].v+p[j].v)/(ans-maxx[i][j]));
62             }
63         }
64     }
65     printf("%.2f\n",an);
66 }
67 
68 int main(){
69     int t;
70     // freopen("in","r",stdin);
71     scanf("%d",&t);
72     while(t--){
73         scanf("%d",&n);
74         for(int i=1;i<=n;i++) scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].v);
75         for(int i=1;i<=n;i++){
76             for(int j=1;j<=n;j++){
77                 a[i][j]=sqrt(1.0*(p[i].x-p[j].x)*(p[i].x-p[j].x)+1.0*(p[i].y-p[j].y)*(p[i].y-p[j].y));
78             }
79         }
80         prim();
81     }
82     return 0;
83 }
View Code

 

WA代码

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <iomanip>
  4 #include <cstring>
  5 #include <climits>
  6 #include <complex>
  7 #include <fstream>
  8 #include <cassert>
  9 #include <cstdio>
 10 #include <bitset>
 11 #include <vector>
 12 #include <deque>
 13 #include <queue>
 14 #include <stack>
 15 #include <ctime>
 16 #include <set>
 17 #include <map>
 18 #include <cmath>
 19 
 20 using namespace std;
 21 
 22 typedef struct Node{
 23     int x;
 24     int y;
 25     double w;
 26 }Node;
 27 
 28 const int maxn = 1111;
 29 int n, m, cnt;
 30 int pre[maxn], vis[maxn], peo[maxn];
 31 int x[maxn], y[maxn], p[maxn];
 32 Node e[maxn<<4];
 33 double mst;
 34 bool use[maxn<<4];
 35 
 36 bool cmp(Node n1, Node n2) {
 37     return n1.w < n2.w;
 38 }
 39 
 40 inline void clear() {
 41     memset(e, 0, sizeof(e));
 42     memset(x, 0, sizeof(x));
 43     memset(y, 0, sizeof(y));
 44     memset(p, 0, sizeof(p));
 45     memset(vis, 0, sizeof(vis));
 46     memset(use, 0, sizeof(use));
 47     memset(peo, 0, sizeof(peo));
 48     m = 0, cnt = 0, mst = 0;
 49 }
 50 
 51 inline void init() {
 52     for(int i = 0; i < maxn; i++) pre[i] = i;
 53 }
 54 
 55 int find(int x) {
 56     return x == pre[x] ? x : pre[x] = find(pre[x]);
 57 }
 58 
 59 bool unite(int x, int y) {
 60     x = find(x);
 61     y = find(y);
 62     if(x != y) {
 63         pre[x] = y;
 64         return 1;
 65     }
 66     return 0;
 67 }
 68 
 69 double dis(int i, int j) {
 70     return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
 71 }
 72 
 73 int main() {
 74     freopen("in", "r", stdin);
 75     int T;
 76     scanf("%d", &T);
 77     while(T--) {
 78         clear();
 79         scanf("%d", &n);
 80         for(int i = 0; i < n; i++) {
 81             scanf("%d %d %d", &x[i], &y[i], &p[i]);
 82         }
 83         for(int i = 0; i < n - 1; i++) {
 84             for(int j = i + 1; j < n; j++) {
 85                 e[m].x = i;
 86                 e[m].y = j;
 87                 e[m++].w = dis(i, j);
 88             }
 89         }
 90         init();
 91         sort(e, e+m, cmp);
 92         for(int i = 0; i < m; i++) {
 93             if(unite(e[i].x, e[i].y)) {
 94                 vis[cnt] = i;
 95                 mst += e[i].w;
 96                 peo[cnt] += p[e[i].x] + p[e[i].y];
 97                 cnt++;
 98             }
 99         }
100         double ans = -1;
101         for(int i = 0; i < n; i++) {
102             for(int j = 0; j < n; j++) {
103                 if(i != j) {
104                     ans = max(ans, (p[i]+p[j]) / (mst-dis(i,j)));
105                 }
106             }
107         }
108         printf("%.2lf\n", ans);
109     }
110     return 0;
111 }
View Code

 

求出最小生成树的同时记录最小生成树中任意两个点之间唯一路径的最大权的边的值,这个只要在要更新树的时候,在已经生成的树中更新就行了

posted @ 2015-11-08 15:32  Kirai  阅读(203)  评论(0)    收藏  举报