zoukankan      html  css  js  c++  java
  • 【BZOJ4819】[Sdoi2017]新生舞会 01分数规划+费用流

    【BZOJ4819】[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

    题解:正常的01分数规划步骤是,先二分答案r,然后将所有点的权值变成a[i]-r*b[i],取最大的k个数,如果最大的k个a[i]-r*b[i]的和>0,说明答案还可以更优,调整下界;否则调整上界

    对于本题来说,我们不能直接排序取前n大,因此需要跑流量为n的最大费用流,如果总费用>0,则说明答案可以更优

    (最大费用流不用说了吧?将边的费用取相反数,然后跑最小费用流)

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    int n,cnt,ans;
    double sum;
    int inq[210],head[210],next[100000],to[100000],flow[100000],re[210],rv[210];
    double dis[210],cost[100000];
    int A[110][110],B[110][110];
    queue<int> q;
    void add(int a,int b,double c)
    {
    	to[cnt]=b,cost[cnt]=-c,flow[cnt]=1,next[cnt]=head[a],head[a]=cnt++;
    	to[cnt]=a,cost[cnt]=c,flow[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
    }
    int bfs()
    {
    	int i,u;
    	for(i=1;i<=2*n+1;i++)	dis[i]=9999999;
    	dis[0]=0,q.push(0);
    	while(!q.empty())
    	{
    		u=q.front(),q.pop(),inq[u]=0;
    		for(i=head[u];i!=-1;i=next[i])
    		{
    			if(flow[i]&&dis[to[i]]>dis[u]+cost[i])
    			{
    				dis[to[i]]=dis[u]+cost[i];
    				re[to[i]]=i,rv[to[i]]=u;
    				if(!inq[to[i]])	inq[to[i]]=1,q.push(to[i]);
    			}
    		}
    	}
    	return dis[2*n+1]<9999999-1e-8;
    }
    bool solve(double sta)
    {
    	memset(head,-1,sizeof(head));
    	int i,j;
    	cnt=0,sum=0;
    	for(i=1;i<=n;i++)
    	{
    		add(0,i,0),add(i+n,2*n+1,0);
    		for(j=1;j<=n;j++)	add(i,j+n,(double)A[i][j]-sta*B[i][j]);
    	}
    	while(bfs())
    	{
    		sum+=dis[2*n+1];
    		for(i=2*n+1;i;i=rv[i])	flow[re[i]]--,flow[re[i]^1]++;
    	}
    	return sum<-1e-8;
    }
    int main()
    {
    	scanf("%d",&n);
    	int i,j,maxx;
    	double l=0,r=0,mid;
    	for(i=1;i<=n;i++)
    	{
    		maxx=0;
    		for(j=1;j<=n;j++)
    		{
    			scanf("%d",&A[i][j]);
    			maxx=max(maxx,A[i][j]);
    		}
    		r+=maxx;
    	}
    	for(i=1;i<=n;i++)	for(j=1;j<=n;j++)	scanf("%d",&B[i][j]);
    	while(r>=l+1e-8)
    	{
    		mid=(l+r)/2;
    		if(solve(mid))	l=mid;
    		else	r=mid;
    	}
    	printf("%.6f",l);
    	return 0;
    }
  • 相关阅读:
    TextView控件中使用android:drawableLeft图片和文字使用gravity只能使文字居中,无法使图片随文字同时居中, 让图片随文字同时居中
    Android Studio sdk无法下载的问题
    CollapsingToolbarLayout的使用,实现向上滑动时,图片自动压缩消失,下拉到最上面图片显示出来
    android studio开发app时,运行时百度地图显示合适,app打包后地图不显示
    两个日期相差的天数
    Android实现定点任务(定时定点做某事)
    Conversion to Dalvik format failed: Unable to execute dex: Cannot merge new index 69457 into a non-jumbo instruction!
    JSP易错点及常用标签
    Java异常机制总结
    java内存区域简单介绍
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6761386.html
Copyright © 2011-2022 走看看