• BZOJ_4819_[Sdoi2017]新生舞会_01分数规划+费用流


    BZOJ_4819_[Sdoi2017]新生舞会_01分数规划+费用流

    Description

    学校组织了一次新生舞会,Cathy作为经验丰富的老学姐,负责为同学们安排舞伴。有n个男生和n个女生参加舞会
    买一个男生和一个女生一起跳舞,互为舞伴。Cathy收集了这些同学之间的关系,比如两个人之前认识没计算得出 
    a[i][j] ,表示第i个男生和第j个女生一起跳舞时他们的喜悦程度。Cathy还需要考虑两个人一起跳舞是否方便,
    比如身高体重差别会不会太大,计算得出 b[i][j],表示第i个男生和第j个女生一起跳舞时的不协调程度。当然,
    还需要考虑很多其他问题。Cathy想先用一个程序通过a[i][j]和b[i][j]求出一种方案,再手动对方案进行微调。C
    athy找到你,希望你帮她写那个程序。一个方案中有n对舞伴,假设没对舞伴的喜悦程度分别是a'1,a'2,...,a'n,
    假设每对舞伴的不协调程度分别是b'1,b'2,...,b'n。令
    C=(a'1+a'2+...+a'n)/(b'1+b'2+...+b'n),Cathy希望C值最大。

    Input

    第一行一个整数n。
    接下来n行,每行n个整数,第i行第j个数表示a[i][j]。
    接下来n行,每行n个整数,第i行第j个数表示b[i][j]。
    1<=n<=100,1<=a[i][j],b[i][j]<=10^4

    Output

    一行一个数,表示C的最大值。四舍五入保留6位小数,选手输出的小数需要与标准输出相等

    Sample Input

    3
    19 17 16
    25 24 23
    35 36 31
    9 5 6
    3 4 2
    7 8 9

    Sample Output

    5.357143

    二分答案x,新的权值为a-b*x。
    题意即求二分图最大带权匹配,转化为最大费用最大流。
     
    代码:
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    typedef double f2;
    #define N 250
    #define M 500050
    #define S (n+n+1)
    #define T (n+n+2)
    int head[N],to[M],nxt[M],flow[M],cnt=1,n,a[105][105],b[105][105],Q[N],l,r;
    int inq[N],path[N];
    f2 val[M],dis[N];
    inline void add(int u,int v,int f,f2 va) {
        to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f; val[cnt]=va;   
        to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0; val[cnt]=-va;
    }
    bool spfa() {
        memset(dis,0xc2,sizeof(dis));
        memset(path,0,sizeof(path));
        dis[S]=0;inq[S]=1;l=r=0;Q[r++]=S;
        while(l!=r) {
            int x=Q[l++],i;if(l==S) l=0; inq[x]=0;
            for(i=head[x];i;i=nxt[i]) {
                if(dis[to[i]]<dis[x]+val[i]&&flow[i]) {
                    dis[to[i]]=dis[x]+val[i];
                    path[to[i]]=i^1;
                    if(!inq[to[i]]) {
                        inq[to[i]]=1; Q[r++]=to[i]; if(r==S) r=0;
                    }
                }
            }
        }
        return path[T];
    }
    bool check(f2 x) {
        int i,j;
        memset(head,0,sizeof(head)); cnt=1;
     
        for(i=1;i<=n;i++) {
            add(S,i,1,0.0);
            add(i+n,T,1,0.0);
        }
        for(i=1;i<=n;i++) {
            for(j=1;j<=n;j++) {
                add(i,n+j,1,a[i][j]-x*b[i][j]);
            }
        }
        f2 maxc=0;
        while(spfa()) {
            int i,nf=1<<30;
            for(i=T;i!=S;i=to[path[i]]) {
                nf=min(nf,flow[path[i]^1]);
            }
            for(i=T;i!=S;i=to[path[i]]) {
                flow[path[i]]+=nf;
                flow[path[i]^1]-=nf;
                maxc+=nf*val[path[i]^1];
            }
        }
        return maxc>=0;
    }
    int main() {
        scanf("%d",&n);
        int i,j;
        for(i=1;i<=n;i++) {
            for(j=1;j<=n;j++) {
                scanf("%d",&a[i][j]);
            }
        }
        for(i=1;i<=n;i++) {
            for(j=1;j<=n;j++) {
                scanf("%d",&b[i][j]);
            }
        }
        f2 ll=0,rr=1000000;
        for(i=1;i<=60;i++) {
            f2 mid=(ll+rr)/2;
            if(check(mid)) ll=mid;
            else rr=mid;
        }
        printf("%.6lf
    ",ll);
    }
    
  • 相关阅读:
    SpringBoot 线程池配置 定时任务,异步任务
    使用Calendar类对时间进行处理
    单例模式的几种实现方式
    一些簡單的入門算法
    OO第四单元博客
    OO第三单元博客
    OO第二单元博客
    OO第一单元博客
    BUAA_OO_2020_Unit4_Wandy
    BUAA_OO_UNIT3_2020
  • 原文地址:https://www.cnblogs.com/suika/p/8998128.html
Copyright © 2020-2023  润新知