bzoj 4819: [Sdoi2017]新生舞会【二分+最小费用最大流】

如果\( b[i]==0 \)那么就是裸的费用流/KM,当然KM快一些但是为什么不写KM呢因为我不会打板子了
考虑二分答案,那么问题变成了判定问题。

\[ans=\frac {a_1+a_2+...+a_n}{b_1+b_2+...+b_n} \]

\[(b_1+b_2+...+b_n)*ans=a_1+a_2+...+a_n \]

\[b_1*ans-a_1+b_2*ans-a_2+...b_n*ans-a_n=0 \]

然后建立费用流模型,看每次是否\( ans\leq 0 \)即可。
!:跑spfa时记得初始化为-inf,跑最长路(因为可能是负数

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=205,inf=1e9;
const double eps=1e-7;
int n,a[N][N],b[N][N],s,t,h[N],cnt,fr[N];
double dis[N],ans;
bool v[N];
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>'9'||p<'0')
    {
        if(p=='-')
            f=-1;
        p=getchar();
    }
    while(p>='0'&&p<='9')
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
struct qwe
{
    int ne,no,to,va;
    double c;
}e[N*N];
void add(int u,int v,int w,double c)
{
    cnt++;
    e[cnt].ne=h[u];
    e[cnt].no=u;
    e[cnt].to=v;
    e[cnt].va=w;
    e[cnt].c=c;
    h[u]=cnt;
}
void ins(int u,int v,int w,double c)
{
    add(u,v,w,c);
    add(v,u,0,-c);
}
bool spfa()
{
    deque<int>q;//因为在洛谷上被卡常所以改成了优化版本(然而还是被KM碾压
    for(int i=s;i<=t;i++)
        dis[i]=-inf;
    dis[s]=0;
    v[s]=1;
    q.push_front(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop_front();
        v[u]=0;
        for(int i=h[u];i;i=e[i].ne)
            if(e[i].va>0&&dis[e[i].to]<dis[u]+e[i].c)
            {
                dis[e[i].to]=dis[u]+e[i].c;
                fr[e[i].to]=i;
                if(!v[e[i].to])
                {
                    v[e[i].to]=1;
                    if(!q.empty()&&dis[e[i].to]>dis[q.front()])
                        q.push_front(e[i].to);
                    else
                        q.push_back(e[i].to);
                }
            }
    }
    return dis[t]!=-inf;
}
void mcf()
{
    int x=inf;
    for(int i=fr[t];i;i=fr[e[i].no])
        x=min(x,e[i].va);
    for(int i=fr[t];i;i=fr[e[i].no])
    {
        e[i].va-=x;
        e[i^1].va+=x;
        ans+=x*e[i].c;
    }
}
bool ok(double x)
{
    cnt=1;ans=0;
    memset(h,0,sizeof(h));
    for(int i=1;i<=n;i++)
        ins(s,i,1,0);
    for(int i=1;i<=n;i++)
        ins(i+n,t,1,0);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            ins(i,j+n,1,a[i][j]-x*(double)b[i][j]);
    while(spfa())
        mcf();
    return ans<=0;
}
int main()
{
    n=read();
    t=2*n+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            a[i][j]=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            b[i][j]=read();
    double l=0.0,r=10000.0;
    while(r-l>=eps)
    {
        double mid=(l+r)/2;
        if(ok(mid))
            r=mid;
        else
            l=mid;
    }
    printf("%.6lf",l);
    return 0;
}
posted @ 2018-01-10 08:22  lokiii  阅读(89)  评论(0编辑  收藏  举报