1. 程式人生 > >[POJ2976][POJ2728]01分數規劃問題的二分答案解法

[POJ2976][POJ2728]01分數規劃問題的二分答案解法

hid nod i++ target spl close itl 生成樹 struct

這裏就不放原題目了。

POJ2976就是01分數規劃的模板題,題目形式就是有n個物品,每個物品有對應的價值ai和代價bi,我們要取K個物品,使取的物品的 技術分享圖片 最小。

二分答案的解法特別妙,我們設 r= 技術分享圖片,那麽就有 技術分享圖片 由此不難發現,只要滿足這條式子,我們能取的r越大越好。

不難發現此時已經滿足二分答案的性質了。

二分r的大小,如果最後式子左邊大於0,那麽說明r取小了,如果左邊小於0,說明r取大了。

那麽我的代碼如下:

技術分享圖片
#include<iostream>
#include<cstdio>
#include<cstring>
#include
<algorithm> using namespace std; int N,K; double a[2000],b[2000]; double de[2000]; int main() { while(1) { scanf("%d%d",&N,&K); if(N==0&&K==0) return 0; for(int i=1;i<=N;i++) scanf("%lf",&a[i]); for(int i=1
;i<=N;i++) scanf("%lf",&b[i]); double l=0,r=1,mid; while(r-l>0.000006) { mid=(l+r)*1.0/2; for(int i=1;i<=N;i++) de[i]=a[i]-mid*b[i]; sort(de+1,de+N+1); long double sum=0; for(int
i=K+1;i<=N;i++) sum+=de[i]; if(sum>0) l=mid; else r=mid; } printf("%.0f\n",mid*100); } }
View Code

而POJ2728就有點小意思了,它是有01劃分性質的一個平面圖最小生成樹。準確來說,是取生成樹的邊第一權值的和比上邊第二權值的和的最小值。

那麽我們還是用上文所述的01分數規劃來做,二分答案,然後把二分出來的r值帶入圖中,用prim去跑一遍。(機房有位大佬不肯放棄kruscal,在卡了一晚上常數之後說了句真香)

於是我的代碼如下(prim未優化)

技術分享圖片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int N;
struct node{
    int x,y,z;
    friend double dis(node a,node b)
    {
        return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y));
    } 
}po[1005];
double edge[1005][1005],tot,high[1005],lowcost[1005];
int close[1005];
double prim(double k)
{
    double cost=0,len=0;
    double sum=0;
    for(int i=1;i<=N;i++)
    {
        close[i]=1;
        lowcost[i]=abs(po[1].z-po[i].z)-edge[1][i]*k;
    }
    /*for(int i=1;i<=N;i++)
        cout<<lowcost[i]<<" ";
    cout<<endl;*/
    close[1]=-1;
    for(int i=1;i<N;i++)
    {
        double minn=1000000000;
        int v=-1;
        for(int j=1;j<=N;j++)
            if(close[j]!=-1&&lowcost[j]<minn)
            {
                v=j;
                minn=lowcost[j];
            }
        if(v!=-1)
        {
            cost+=abs(po[close[v]].z-po[v].z);
            len+=edge[close[v]][v];
            close[v]=-1;
            sum+=lowcost[v];
            for(int j=1;j<=N;j++)
            {
                double tmp=abs(po[v].z-po[j].z)-edge[v][j]*k;
                if(close[j]!=-1&&tmp<lowcost[j])
                {
                    lowcost[j]=tmp;
                    close[j]=v;
                }
            }
        }
    }
    //cout<<k<<" "<<sum<<endl;
    return sum;
}
int main()
{
    while(1)
    {
        scanf("%d",&N);
        if(N==0)
            return 0;
        for(int i=1;i<=N;i++)
            scanf("%d%d%d",&po[i].x,&po[i].y,&po[i].z);
        for(int i=1;i<=N;i++)
            for(int j=1;j<=N;j++)
                edge[i][j]=dis(po[i],po[j]);
        double l=0.0,r=100.0,mid;
        while(r-l>1e-6)
        {
            mid=(l+r)/2;
            if(prim(mid)>=0)
                l=mid;
            else
                r=mid;
        }
        printf("%.3f\n",l);
    }
}
View Code

[POJ2976][POJ2728]01分數規劃問題的二分答案解法