• 【BZOJ4819】新生舞会(SDOI2017)-01分数规划+费用流


    测试地址:新生舞会
    做法:本题需要用到01分数规划+费用流。
    首先看到题目中那个式子,就差不多能想到01分数规划了。按照套路处理:二分比值C,转化为判定性问题,即存不存在大于C的比值,把分母乘到另一边,再减回来,得到AiCBi>0这个式子,在这道题中,就是按边权为AijCBij建二分图,然后问有没有一个匹配的权值和大于0,那么我们当然是求最佳匹配,这就是费用流的经典应用之一了。
    (但是实际测试中,分点测试的情况下貌似会被卡,更好的KM算法有待学习)
    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const double eps=1e-8;
    const double inf=1000000000.0;
    int n,s,t,first[210],tot;
    int hd,tl,q[8000010],last[210],laste[210];
    double a[110][110],b[110][110],dis[210];
    bool vis[210]={0};
    struct edge
    {
        int v,next,f;
        double c;
    }e[50010];
    
    void insert(int a,int b)
    {
        e[++tot].v=b,e[tot].next=first[a],first[a]=tot;
        e[++tot].v=a,e[tot].next=first[b],first[b]=tot;
    }
    
    void maxflow()
    {
        for(int i=1;i<=2*n+2;i++)
            dis[i]=-inf;
        dis[s]=0.0;
        vis[s]=1;
        q[1]=s;
        hd=tl=1;
        while(hd<=tl)
        {
            int v=q[hd++];
            for(int i=first[v];i;i=e[i].next)
            {
                if (e[i].f&&dis[e[i].v]<dis[v]+e[i].c)
                {
                    dis[e[i].v]=dis[v]+e[i].c;
                    last[e[i].v]=v;laste[e[i].v]=i;
                    if (!vis[e[i].v]) vis[e[i].v]=1,q[++tl]=e[i].v;
                }
            }
            vis[v]=0;
        }
    }
    
    bool check(double c)
    {
        double ans=0.0;
        int step=0;
    
        tot=1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
            {
                e[++tot].f=1,e[tot].c=a[i][j]-c*b[i][j];
                e[++tot].f=0,e[tot].c=c*b[i][j]-a[i][j];
            }
        for(int i=1;i<=n;i++)
        {
            e[++tot].f=1,e[tot].c=0.0;
            e[++tot].f=0,e[tot].c=0.0;
            e[++tot].f=1,e[tot].c=0.0;
            e[++tot].f=0,e[tot].c=0.0;
        }
    
        while(step<n)
        {
            maxflow();
            ans+=dis[t];
            step++;
            int x=t;
            while(x!=s)
            {
                e[laste[x]].f--;
                e[laste[x]^1].f++;
                x=last[x];
            }
        }
        return ans>eps;
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%lf",&a[i][j]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%lf",&b[i][j]);
    
        tot=1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                insert(i,n+j);
        s=2*n+1,t=2*n+2;
        for(int i=1;i<=n;i++)
        {
            insert(s,i);
            insert(n+i,t);
        }
    
        double l=0.0,r=10000.0;
        while(r-l>=eps)
        {
            double mid=(l+r)/2.0;
            if (check(mid)) l=mid;
            else r=mid;
        }
        printf("%.6lf",l);
    
        return 0;
    }
  • 相关阅读:
    BZOJ-2743: [HEOI2012]采花(树状数组 or TLE莫队)
    BZOJ-1122: [POI2008]账本BBB (单调栈神题)
    2017年10月18日23:54:18
    [校内自测 NOIP模拟题] chenzeyu97要请客(单调栈)
    BZOJ-1057: [ZJOI2007]棋盘制作(单调栈)
    [校内自测] 奶牛编号 (递推+智商)
    [校内自测] Incr (LIS+智商)
    BZOJ1486 [HNOI2009]最小圈
    BZOJ2400 Spoj 839 Optimal Marks
    BZOJ2595 [Wc2008]游览计划
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793472.html
Copyright © 2020-2023  润新知