zoukankan      html  css  js  c++  java
  • 【BZOJ4819】新生舞会(分数规划,网络流)

    【BZOJ4819】新生舞会(分数规划,网络流)

    题面

    BZOJ

    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

    题解

    很明显的分数规划了
    二分一个答案
    现在要让(sum a-mid·sum bgeq 0)
    显然是要求二分图的最大带权匹配
    (KM)算法早就不会了
    直接上费用流就行了

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 111
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    struct Line{int v,next,w;double fy;}e[MAX*MAX*2];
    int h[MAX<<1],cnt;
    inline void Add(int u,int v,int w,double fy)
    {
    	e[cnt]=(Line){v,h[u],w,fy};h[u]=cnt++;
    	e[cnt]=(Line){u,h[v],0,-fy};h[v]=cnt++;
    }
    double dis[MAX<<1],Cost;
    bool vis[MAX<<1];
    int n,S,T,pe[MAX<<1],pv[MAX<<1];
    int a[MAX][MAX],b[MAX][MAX];
    bool SPFA()
    {
    	queue<int> Q;Q.push(S);
    	for(int i=S;i<=T;++i)dis[i]=-1e18;
    	dis[S]=0;vis[S]=true;
    	while(!Q.empty())
    	{
    		int u=Q.front();Q.pop();
    		for(int i=h[u];i;i=e[i].next)
    		{
    			int v=e[i].v;
    			if(e[i].w&&dis[v]<dis[u]+e[i].fy)
    			{
    				dis[v]=dis[u]+e[i].fy;
    				pe[v]=i;pv[v]=u;
    				if(!vis[v])vis[v]=true,Q.push(v);
    			}
    		}
    		vis[u]=false;
    	}
    	if(dis[T]<=-1e18)return false;
    	for(int i=T;i!=S;i=pv[i])e[pe[i]].w--,e[pe[i]^1].w++;
    	Cost+=dis[T];
    	return true;
    }
    void Build(double mid)
    {
    	for(int i=S;i<=T;++i)h[i]=0;cnt=2;
    	for(int i=1;i<=n;++i)Add(S,i,1,0);
    	for(int i=1;i<=n;++i)Add(i+n,T,1,0);
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=n;++j)
    			Add(i,j+n,1,1.0*a[i][j]-mid*b[i][j]);
    	Cost=0;
    }
    bool check(double mid)
    {
    	Build(mid);
    	while(SPFA());
    	return Cost>=0;
    }
    int main()
    {
    	n=read();S=0;T=n+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,r=1e4;
    	while(r-l>1e-7)
    	{
    		double mid=(l+r)/2;
    		if(check(mid))l=mid;
    		else r=mid;
    	}
    	printf("%.6lf
    ",l);
    	return 0;
    }
    
    
  • 相关阅读:
    HDU 5938 Four Operations 【贪心】(2016年中国大学生程序设计竞赛(杭州))
    HDU 5935 Car 【模拟】 (2016年中国大学生程序设计竞赛(杭州))
    HDU 5934 Bomb 【图论缩点】(2016年中国大学生程序设计竞赛(杭州))
    HDU 5933 ArcSoft's Office Rearrangement 【模拟】(2016年中国大学生程序设计竞赛(杭州))
    HDU 5929 Basic Data Structure 【模拟】 (2016CCPC东北地区大学生程序设计竞赛)
    【转】LaTeX 符号命令大全
    HDU 5922 Minimum’s Revenge 【模拟】 (2016CCPC东北地区大学生程序设计竞赛)
    HDU 5927 Auxiliary Set 【DFS+树】(2016CCPC东北地区大学生程序设计竞赛)
    数据结构之稀疏矩阵
    C++中引用(&)的用法和应用实例
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9086633.html
Copyright © 2011-2022 走看看