【POJ2728】Desert King 最優比率生成樹
阿新 • • 發佈:2018-12-06
esp stream 問題 ring 規劃 i++ names mat else
題目大意:給定一個 N 個點的無向完全圖,邊有兩個不同性質的邊權,求該無向圖的一棵最優比例生成樹,使得性質為 A 的邊權和比性質為 B 的邊權和最小。
題解:要求的答案可以看成是 0-1 分數規劃問題,即:選定一個數 mid,每次重新構建邊權為 \(a[i]-mid*b[i]\) 的圖,再在圖上跑一遍最小生成樹(這裏由於是完全圖,應該采用 Prim 算法)判斷最小值和給定判定的最小值的關系即可,這裏為:若最小值大於 mid,則下界提高,否則上界下降。
代碼如下
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn=1010; const double eps=1e-5; int n;bool vis[maxn]; double cost[maxn][maxn],d[maxn][maxn],mp[maxn][maxn],x[maxn],y[maxn],h[maxn],mx,s[maxn]; inline double calc(int i,int j){ return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])); } void read_and_parse(){ for(int i=1;i<=n;i++)scanf("%lf%lf%lf",&x[i],&y[i],&h[i]); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++){ cost[i][j]=cost[j][i]=fabs(h[i]-h[j]); d[i][j]=d[j][i]=calc(i,j); mx=max(mx,cost[i][j]/d[i][j]); } } double prim(){ fill(vis+1,vis+n+1,0); double res=0; s[1]=0,vis[1]=1; for(int i=1;i<=n;i++)s[i]=mp[1][i]; for(int i=1;i<n;i++){ int u=0; for(int j=1;j<=n;j++)if(!vis[j]&&(!u||s[j]<s[u]))u=j; vis[u]=1,res+=s[u]; for(int v=1;v<=n;v++)if(!vis[v])s[v]=min(s[v],mp[u][v]); } return res; } bool check(double mid){ for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) mp[i][j]=mp[j][i]=cost[i][j]-mid*d[i][j]; return prim()>0; } void solve(){ double l=0,r=mx; while(r-l>eps){ double mid=(l+r)/2.0; if(check(mid))l=mid; else r=mid; } printf("%.3lf\n",l); } int main(){ while(scanf("%d",&n)&&n){ read_and_parse(); solve(); } return 0; }
【POJ2728】Desert King 最優比率生成樹