zoukankan      html  css  js  c++  java
  • bzoj 4819: [Sdoi2017]新生舞会

    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

    HINT

     

    Source

     
    二分+费用流
     
    难得见到这么送的网络流啊;
    0/1分数规划,二分一个答案之后
    (a1+a2...+an)/(b1+b2...+bn)>=mid;
    乘过去再移项,变形之后变为:
    sigma(ai-mid*bi)>=0
    那么把边的费用变为ai-mid*bi,求一遍最大费用是否>=0即可,很naive啊
    (define int long long 了常数有点大)
    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #define RG register
    #define int long long
    using namespace std;
    typedef long long ll;
    const int N=100000;
    const double eps=1e-9;
    const double Inf=19260817.0; 
    int gi() {
    	int x=0,flag=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-') flag=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return x*flag;
    }
    int n,ans,flag1,flag2;
    int head[N],nxt[N],to[N],s[N],cnt=1,S,T;
    double cc[N],dis[N],cost;
    int a[300][300],b[300][300];
    int level[N],q[N*10],F,fa[N],W[N];
    struct data {
    	int l,r,s,t;
    } hh[N];
    inline void Addedge(RG int x,RG int y,RG int z,RG double u) {
    	to[++cnt]=y,s[cnt]=z,cc[cnt]=u,nxt[cnt]=head[x],head[x]=cnt;
    }
    inline void lnk(RG int x,RG int y,RG int z,RG double u) {
    	Addedge(x,y,z,u),Addedge(y,x,0,-u);
    }
    inline bool spfa() {
    	for(RG int i=S; i<=T; i++) dis[i]=Inf,W[i]=0;
    	RG int t=0,sum=1;
    	q[0]=S,W[S]=1,dis[S]=0;
    	while(t<sum) {
    		RG int x=q[t++];
    		W[x]=0;
    		for(RG int i=head[x];i;i=nxt[i]) {
    			RG int y=to[i];
    			if(s[i]&&dis[y]-(dis[x]+cc[i])>=eps) {
    				dis[y]=dis[x]+cc[i];
    				fa[y]=i;
    				if(!W[y]) W[y]=1,q[sum++]=y;
    			}
    		}
    	}
    	if(dis[T]==Inf) return 0;
    	RG int f=Inf;
    	for(RG int i=fa[T];i;i=fa[to[i^1]]) f=min(f,s[i]);
    	for(RG int i=fa[T];i;i=fa[to[i^1]]) s[i]-=f,s[i^1]+=f;
    	cost+=dis[T]*f;
    	return 1;
    }
    inline void Maxcost() {
    	while(spfa()); 
    }
    inline bool check(RG double mid){
    	cnt=1;memset(head,0,sizeof(head));
    	for(RG int i=1;i<=n;i++)
    	   for(RG int j=1;j<=n;j++)
    	     lnk(i,j+n,1,-(a[i][j]-mid*b[i][j]));
    	for(RG int i=1;i<=n;i++) lnk(S,i,1,0),lnk(i+n,T,1,0);
    	cost=0;Maxcost();cost=-cost;
    	return cost-0>=eps;
    }
    main() {
    	freopen("1.in","r",stdin);
    	n=gi();S=0,T=2*n+1;
    	for(RG int i=1;i<=n;i++)
    		for(RG int j=1;j<=n;j++)
    			a[i][j]=gi();
    	for(RG int i=1;i<=n;i++)
    	   for(RG int j=1;j<=n;j++)
    	        b[i][j]=gi();
    	double l=0,r=10000.0,ans=0;
    	while(r-l>=eps){
    		double mid=(l+r)/2;
    		if(check(mid)) l=mid,ans=mid;
    		else r=mid;
    	}
    	printf("%.6f",ans);
    }
    

      

  • 相关阅读:
    php 多进程
    关于TP的RBAC的使用
    谈谈自己对于Auth2.0的见解
    php 写队列
    关于thinkphp中Hook钩子的解析
    JS的闭包
    单链表的查找和取值-1
    shell输入输出重定向
    转-Visual Studio控制台程序输出窗口一闪而过的解决方法
    linux下如何调用不同目录下的.h 库文件
  • 原文地址:https://www.cnblogs.com/qt666/p/6696674.html
Copyright © 2011-2022 走看看