【POJ2728】沙漠王國Desert King-最優比率生成樹-01分數規劃
阿新 • • 發佈:2020-09-01
Description
大衛剛被選舉為沙漠王國的國王。為了贏得人們的尊重,他決定修建渠道,把水引到整個國家的每個村莊。使得連線到中心村莊的所有村莊都將會被灌溉。經過多天的研究,他最終制定出目的。就是使建造渠道每英里的平均價格最小。換句話說,建造渠道的總體成本與總長度的比值必須最小。只需要建立必須的渠道,把水引到所有的村莊即可。也就是每個村莊僅一種方式連線到中心村莊。
已知每個村莊的位置和高度,任意兩個村莊之間的渠道必須是直的。長度為這兩個村莊(x1,y1)和(x2,y2)之間的距離sqrt((x1-x2)2+(y1-y2)2),建立渠道的花費為這兩個村莊高度差的絕對值。每個村莊都在不同高度,注意水能夠通過特殊的裝置從低處流到高處(不考慮裝置費用),沒有任意三個村莊位於同一條水平線上。現在國王想知道建造渠道每英里的平均價格最小是多少?
Input
輸入有多組測試資料;
每組測試資料第一行包含一個整數N(2<=N<=1000),表示村莊的個數。
接下來n行,每行三個整數x,y和z(0<=x,y<10000,0<=z<10000000),表示一個村莊位於(x,y)這點,高度為z,檔案最後一行以一個0作為結束,不用處理。
Output
對於每組測試資料,輸出一行為建造渠道的總體成本與總長度的比值,保留三位小數。
Sample Input
4
0 0 0
0 1 1
1 1 2
1 0 3
0
Sample Output
1.000
思路
- 最優比率生成樹(01分數規劃運用例項)
- 完全圖用prim
- 標準上界應該為high之和/min(dis),但1e5也能過
程式碼
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; int n,flag[1005]; double dis[1005][1005],high[1005][1005],d[1005]; struct fdfdfd{double x,y,z;}e[1005]; double js(int i,int j){return sqrt((e[i].x-e[j].x)*(e[i].x-e[j].x)+(e[i].y-e[j].y)*(e[i].y-e[j].y));} bool prim(double x) { double sum=0; memset(flag,0,sizeof(flag)); memset(d,0x7f,sizeof(d)); d[1]=0; for(int i=1;i<=n;++i) { double minn=0x7fffffff; int k=-1; for(int j=1;j<=n;++j) if(!flag[j]&&d[j]<minn) minn=d[j],k=j; flag[k]=1; sum+=d[k]; for(int j=1;j<=n;++j) if(!flag[j]) d[j]=min(d[j],high[k][j]-x*dis[k][j]); } return (sum>0); } int main() { while(scanf("%d",&n)) { if(!n) break; for(int i=1;i<=n;++i) scanf("%lf%lf%lf",&e[i].x,&e[i].y,&e[i].z); for(int i=1;i<=n;++i) for(int j=i+1;j<=n;++j) { dis[i][j]=dis[j][i]=js(i,j); high[i][j]=high[j][i]=fabs(e[i].z-e[j].z); } double l=0,r=100000; while(r-l>1e-8) { double mid=(r+l)/2.0; if(prim(mid)) l=mid; else r=mid; } printf("%.3f\n",l); } return 0; }