zoukankan      html  css  js  c++  java
  • [POJ2976][POJ2728]01分数规划问题的二分答案解法

    这里就不放原题目了。

    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
    ",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
    ",l);
        }
    }
    View Code
  • 相关阅读:
    ZJOI2017
    李超线段树
    单调性优化dp
    ZJOI2018 树
    【ZJOI2017】汉诺塔
    暂存
    聚类的方法(层次聚类,K-means聚类)
    哈希表(散列表)
    多路查找树B树
    二叉排序树
  • 原文地址:https://www.cnblogs.com/sherrlock/p/9631693.html
Copyright © 2011-2022 走看看