BZOJ4819:[SDOI2017]新生舞会

4819: [Sdoi2017]新生舞会

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 783  Solved: 396
[Submit][Status][Discuss]

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
 
思路{
   比较裸的分数规划吧。。。
   由于昨天HN女队出了一道最大权闭合子图+分数规划,辣鸡的我没有看出来.就决心练一练.
   首先这是个二分图。虚拟源汇点连容量为1的边,考虑怎么得解。
   分数规划的套路是∑ai/∑bi=g,移项得∑ai-g*∑bi=0然后二分答案g都可以了;
   由于最大化g,考虑最大费用最大流,那么每两个连(-ai+g*bi)的边,直接费用流即可.
}
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf (1<<30)
#define il inline
#define RG register
#define db double
#define LL long long
#define maxx 301
using namespace std;
struct ed{int nxt,to,c;db w;}e[maxx*maxx*6];
int head[maxx*2],tot;
void add(int u,int v,int c,db w){
	e[tot].to=v;e[tot].nxt=head[u];
	e[tot].c=c;e[tot].w=w;head[u]=tot++;
}
void ADD(int u,int v,int c,db w){
	add(u,v,c,w);
	add(v,u,0,-w);
}
int pre[maxx],flow;
db dis[maxx],ans;
bool in[maxx];
queue<int>que;
bool SPFA(int s,int t){
	memset(dis,127,sizeof(dis));memset(in,false,sizeof(in));db SS=dis[0];
	que.push(s),in[s]=true;dis[s]=0;
	while(!que.empty()){
		int u=que.front();que.pop(),in[u]=false;
		for(int i=head[u];i!=-1;i=e[i].nxt){
			if((!e[i].c)||dis[e[i].to]<=dis[u]+e[i].w)continue;
			int v=e[i].to;dis[v]=dis[u]+e[i].w;
			pre[v]=i;
			if(!in[v])in[v]=true,que.push(v);
		}
	}if(dis[t]==SS)return false;
	return true;
}
db get(int s,int t){
	int u,p,sum=66666666;db Ans=0;
	for(u=t;u!=s;u=e[p^1].to)p=pre[u],sum=min(sum,e[p].c);
	for(u=t;u!=s;u=e[p^1].to)p=pre[u],e[p].c-=sum,e[p^1].c+=sum,Ans+=sum*e[p].w;
	flow+=sum;return Ans;
}
db mincostflow(int s,int t){flow=0;ans=0.000;
	while(SPFA(s,t))ans+=get(s,t);return ans;
}
int n,a[maxx][maxx],b[maxx][maxx];
#define eps 0.0000001
il void work(){
	scanf("%d",&n);
	for(RG int i=1;i<=n;++i)
		for(RG int j=1;j<=n;++j)scanf("%d",&a[i][j]);
	for(RG int i=1;i<=n;++i)
		for(RG int j=1;j<=n;++j)scanf("%d",&b[i][j]);
	db l=0.000,r=1000000.000;
	while(r-l>eps){
		memset(head,-1,sizeof(head));tot=0;
		db mid=(l+r)/2;for(int i=1;i<=n;++i)ADD(0,i,1,0);
		for(int i=n+1;i<=(n<<1);++i)ADD(i,((n<<1)|1),1,0);
		for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)ADD(i,n+j,1,-a[i][j]+b[i][j]*mid);
		db aa=-mincostflow(0,((n<<1)|1));
		if(aa>0)l=mid+eps;else r=mid-eps;
	}printf("%.6lf",(l+r)/2);
}
int main(){
    work();
    return 0;
}

 

posted @ 2017-07-11 15:59  QYP_2002  阅读(162)  评论(0编辑  收藏  举报