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;
    }
    
    
  • 相关阅读:
    Ubuntu 16.09下iptables通过raw表实现日志输出和调试
    CentOS 6.9永久设置静态路由表以及路由表常用设置
    Linux下添加静态路由表设置网关出现SIOCADDRT: Network is unreachable的问题分析
    Linux下使用ISC DHCP可以实现动态推送静态路由表
    Linux下使用ping出现destination is unreachable的问题可能性
    树莓派(Debian)系统开启iptables的raw表实现日志输出
    MySQL时间戳与日期互转
    树莓派(Debian)系统设置了静态IP之后还会获取动态IP的问题解决(scope global secondary eth0)
    Linux下同一网段内的IP中两台主机通信不经过路由器(ARP)(转)
    OpenWrt包管理软件opkg的使用(极路由)
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9086633.html
Copyright © 2011-2022 走看看