poj 2728 Desert King(最小比率產生樹,迭代法)

來源:互聯網
上載者:User

標籤:des   style   blog   color   os   資料   

引用別人的解釋:

題意:有n個村莊,村莊在不同座標和海拔,現在要對所有村莊供水,只要兩個村莊之間有一條路即可,

         建造水管距離為座標之間的歐幾裡德距離(好象是叫歐幾裡德距離吧),費用為海拔之差

         現在要求方案使得費用與距離的比值最小

很顯然,這個題目是要求一棵最優比率產生樹,



概念

有帶權圖G, 對於圖中每條邊e[i], 都有benifit[i](收入)和cost[i](花費), 我們要求的是一棵產生樹T, 它使得 ∑(benifit[i]) / ∑(cost[i]), i∈T 最大(或最小).

這顯然是一個具有現實意義的問題.

 

解法之一 0-1分數規劃

設x[i]等於1或0, 表示邊e[i]是否屬於產生樹.

則我們所求的比率 r = ∑(benifit[i] * x[i]) / ∑(cost[i] * x[i]), 0≤i<m .

為了使 r 最大, 設計一個子問題---> 讓 z = ∑(benifit[i] * x[i]) - l * ∑(cost[i] * x[i]) = ∑(d[i] * x[i]) 最大 (d[i] = benifit[i] - l * cost[i]) , 並記為z(l). 我們可以興高采烈地把z(l)看做以d為邊權的最大產生樹的總權值.

 


然後明確兩個性質:

 1.  z單調遞減

  證明: 因為cost為正數, 所以z隨l的減小而增大.

 2.  z( max(r) ) = 0

  證明: 若z( max(r) ) < 0, ∑(benifit[i] * x[i]) - max(r) * ∑(cost[i] * x[i]) < 0, 可化為 max(r) < max(r). 矛盾;

          若z( max(r) ) >= 0, 根據性質1, 當z = 0 時r最大.

到了這個地步, 七竅全已打通, 喜歡二分的上二分, 喜歡Dinkelbach的就Dinkelbach.

 

複雜度

時間 O( O(MST) * log max(r) )

空間 O( O(MST) )


迭代+prim

 

#include<stdio.h>#include<math.h>#include<string.h>#include<limits.h>#define MAX 1100double x[MAX],y[MAX],z[MAX];double cost[MAX][MAX],dist[MAX][MAX];int n;double prim(double);int main(void){    int i,j;    while(scanf("%d",&n)&&n){        for(i=1;i<=n;i++){//讀取資料            scanf("%lf%lf%lf",&x[i],&y[i],&z[i]);        }        //處理 任意點之間的長度和價值        for(i=1;i<=n;i++){             for(j=i+1;j<=n;j++){                double d=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);                dist[i][j]=dist[j][i]=sqrt(d);                double c=z[i]-z[j];                if(c<0) c=-c;                cost[i][j]=cost[j][i]=c;                            }        }        //判斷給定的rate是否在誤差之內        double a=0,b=0; //初始r為0        while(1)        {            b = prim(a);            if(fabs(a-b)<1e-4)  break;            a=b;        }                 printf("%.3lf\n",b);              }    return 0;}double prim(double p){    int visit[MAX],father[MAX];    double dis[MAX];    int i,j;    //訪問數組初始化    memset(visit,0,sizeof(visit));    visit[1]=1;    //對已加入的最小產生樹的頂點集合 計算它的父節點    for(i=2;i<=n;i++){        dis[i]=cost[1][i]-p*dist[1][i];        father[i]=1;    }                    int k=0;    double totalCost=0,totalDist=0;    //prim求最小產生樹    for(i=1;i<n;i++){        k=0;        double mincost=INT_MAX;//最大值,最好是這個        for(j=2;j<=n;j++){            if(!visit[j]&&dis[j]<mincost) {                mincost=dis[j];k=j;            }        }                if(k==0) break;        visit[k]=1;        totalCost+=cost[ father[k] ][k];        totalDist+=dist[ father[k] ][k];                for(j=1;j<=n;j++){            double h=cost[k][j]-p*dist[k][j];            if(!visit[j]&&dis[j]>h){                dis[j]=h;                father[j]=k;            }        }            }    return totalCost/totalDist;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.