先求出最小生成树,然后枚举树上的边,对于每条边“分别”找出这条割边形成的两个块中点权最大的两个
1.因为结果是A/B。A的变化会引起B的变化,两个制约。无法直接贪心出最大的A/B。故要通过枚举
2.无论magic road要加在哪里。加的边是否是最小生成树上的边,都会产生环,我们都要选择一条边删掉
注意删掉的边必须是树的环上的边。为了使结果最大。即找出最大的边
3.能够枚举两点。找出边,也能够枚举边,找出点,我是用后者。感觉比較easy写也好理解
#include <cstdio> #include <cstdlib> #include <iostream> #include <algorithm> #include <vector> #include <cstring> #include <cmath> using namespace std; const int INF=(1<<31)-1; int num; bool visit[1111]; struct city{int x,y,popu;}point[1111]; vector<int>G[1111]; double getdis(city& a,city& b) { double dx=a.x-b.x; double dy=a.y-b.y; return sqrt(dx*dx+dy*dy); } double dis[1111][1111]; double prim() { double sum=0; double dist[1111]; fill(dist,dist+1111,INF*1.0); double minedge=INF; int now=1,min_p; int pre[1111]; memset(pre,0,sizeof(pre)); dist[now]=0; visit[1]=true; for(int t=1;t<num;t++) { for(int i=1;i<=num;i++) { if(i!=now && !visit[i] &&dist[i]>dis[now][i]) { pre[i]=now; dist[i]=dis[now][i]; } } minedge=INF; for(int i=1;i<=num;i++) { if(!visit[i]&&minedge>dist[i]) { minedge=dist[i]; min_p=i; } } G[pre[min_p]].push_back(min_p); G[min_p].push_back(pre[min_p]); sum+=dis[min_p][pre[min_p]]; now=min_p; visit[now]=true; } return sum; } int dfs(int v,int fa) { int maxn=point[v].popu; for(int j=0;j<G[v].size();j++) { if(G[v][j]!=fa) { maxn=max(maxn,dfs(G[v][j],v)); } } return maxn; } int main() { #ifndef ONLINE_JUDGE freopen("G:/1.txt","r",stdin); freopen("G:/2.txt","w",stdout); #endif int T; scanf("%d",&T); while(T--) { scanf("%d",&num); for(int i=1;i<=num;i++) { scanf("%d%d%d",&point[i].x,&point[i].y,&point[i].popu); } for(int i=1;i<=num;i++) { for(int j=1;j<=num;j++) { dis[i][j]=getdis(point[i],point[j]); } } double sum=prim(); double ans=0; for(int i=1;i<=num;i++) { for(int j=0;j<G[i].size();j++) { int t1=dfs(i,G[i][j]); int t2=dfs(G[i][j],i); ans=max(ans,(t1+t2)*1.0/(sum-dis[i][G[i][j]])); } } //ans+=(1e-8); printf("%.2f\n",ans); for(int i=1;i<=num;i++) { G[i].clear(); } memset(point,0,sizeof(city)*(num+1)); memset(visit,0,sizeof(bool)*(num+1)); } }