[SDOI2017]新生舞会 题解

 

首先是题目链接:

luogu:https://www.luogu.com.cn/problem/P3705

loj:https://loj.ac/problem/2003

bzoj:http://www.lydsy.com/JudgeOnline/problem.php?id=4819


发现题目要求 [SDOI2017]新生舞会 题解最大化

稍作变形得 [SDOI2017]新生舞会 题解

于是容易想到二分答案[SDOI2017]新生舞会 题解,并将第[SDOI2017]新生舞会 题解个男生和第[SDOI2017]新生舞会 题解个女生连一条权值为[SDOI2017]新生舞会 题解的边,用KM算法进行带权二分图最大匹配。

如果匹配结果大于等于[SDOI2017]新生舞会 题解,则答案小于等于[SDOI2017]新生舞会 题解

代码:

#include<bits/stdc++.h>
#define rep(i,a,b) for(register int i=a;i<=b;++i)
#define N 110
#define INF 1000000007
inline int read()
{
    bool f=0;int x=0;char ch;
    do{ch=getchar();f|=(ch=='-');}while(!isdigit(ch));
    do{x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}while(isdigit(ch));
    return f?-x:x;
}
using namespace std;
int n,a[N][N],b[N][N],match[N];
double lx[N],ly[N],val[N][N];
bool vx[N],vy[N];
bool dfs(int x)
{
    vx[x]=1;
    rep(y,1,n)
        if(!vy[y]&&lx[x]+ly[y]-val[x][y]==0)
        {
            vy[y]=1;
            if(match[y]==-1||dfs(match[y]))
            {
                match[y]=x;
                return 1;
            }
        }
    return 0;
}
inline bool KM()
{
    memset(ly,0.0,sizeof(ly));
    rep(i,1,n)
    {
        lx[i]=-INF;
        rep(j,1,n)lx[i]=max(lx[i],val[i][j]);
    }
    memset(match,-1,sizeof(match));
    rep(i,1,n)
        while(1)
        {
            memset(vx,0,sizeof(vx));
            memset(vy,0,sizeof(vy));
            if(dfs(i)) break;
            double d=INF;
            rep(x,1,n)if(vx[x])
                rep(y,1,n)if(!vy[y])
                    d=min(d,lx[x]+ly[y]-val[x][y]);
            if(d==INF) return -1;
            rep(x,1,n) if(vx[x])
                lx[x]-=d;
            rep(y,1,n) if(vy[y])
                ly[y]+=d;
        }
    double res=0;
    rep(i,1,n) if(match[i]>-1)
        res+=val[match[i]][i];
    return res>0;
}
int main()
{
    n=read();
    rep(i,1,n)rep(j,1,n) a[i][j]=read();
    rep(i,1,n)rep(j,1,n) b[i][j]=read();
    double l=0,r=1e4,mid;
    while(r-l>=1e-8)
    {
        mid=l+(r-l)/2;
        rep(i,1,n)rep(j,1,n)val[i][j]=1.0*a[i][j]-mid*b[i][j];
        if(KM()) l=mid;
        else r=mid;
    }
    printf("%.6lf",mid);
    return 0;
}

 


上一篇:[题解] LuoguP3702 [SDOI2017]序列计数


下一篇:c++ & 的一些用法(参考)