BZOJ 4819 SDOI2017 新生舞会
4819: [Sdoi2017]新生舞会
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1239 Solved: 642
[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
19 17 16
25 24 23
35 36 31
9 5 6
3 4 2
7 8 9
Sample Output
5.357143
HINT
Source
二分+费用流
首先二分答案mid 那么原问题的判断就变成了 a1+a2+a3+....+an>=mid*(b1+b2+b3+....+bn)
建图的话 i向j连一条ai-bj的边即可 最后跑费用流看一下最大费用是否大于等于0即可
/************************************************************** Problem: 4819 User: zhangenming Language: C++ Result: Accepted Time:5648 ms Memory:5296 kb ****************************************************************/ #include <bits/stdc++.h> #define ll long long #define eps 1e-7 #define inf 1e9+10 using namespace std; inline int read(){ int x=0;int f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} return x*f; } const int MAXN=1e5+10; inline void print(double t){ printf("%.6lf\n",t); } struct node{ int y,next,f,back; double w; }e[MAXN]; int linkk[MAXN],len,n,m,a[110][110],b[110][110],vis[MAXN],s,t; double dis[MAXN],ans; inline void insert(int x,int y,int f,double w){ e[++len].y=y;e[len].next=linkk[x];linkk[x]=len;e[len].back=len+1;e[len].f=f;e[len].w=w; e[++len].y=x;e[len].next=linkk[y];linkk[y]=len;e[len].back=len-1;e[len].f=0;e[len].w=-w; } inline bool spfa(){ deque<int> q;q.push_back(t); for(int i=s;i<=t;i++) vis[i]=0,dis[i]=-inf; vis[t]=1;dis[t]=0; while(!q.empty()){ int tn=q.front();q.pop_front(); for(int i=linkk[tn];i;i=e[i].next){ if(e[e[i].back].f&&dis[e[i].y]<dis[tn]-e[i].w){ dis[e[i].y]=dis[tn]-e[i].w; if(!vis[e[i].y]){ if(!q.empty()&&dis[e[i].y]>dis[q.front()]) q.push_front(e[i].y); else q.push_back(e[i].y); vis[e[i].y]=1; } } } vis[tn]=0; } //printf("%.6lf\n",dis[s]); return dis[s]!=-inf; } inline int getcost(int x,int flow){ vis[x]=1;int f=0,d; if(x==t) return flow; for(int i=linkk[x];i;i=e[i].next){ if(e[i].f&&dis[e[i].y]==dis[x]-e[i].w&&!vis[e[i].y]){ if(d=getcost(e[i].y,min(flow-f,e[i].f))){ f+=d;e[i].f-=d;e[e[i].back].f+=d; //cout<<d<<' ';print(e[i].w); ans+=1.0*d*e[i].w;if(f==flow) return flow; } } } return f; } inline void zkw(){ while(spfa()){ vis[t]=1; while(vis[t]){ for(int i=s;i<=t;i++) vis[i]=0; getcost(s,inf); } } } inline bool solve(double mid){ //print(mid); for(int i=s;i<=t;i++) linkk[i]=0; len=0; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ insert(i,j+n,1,a[i][j]-1.0*mid*b[i][j]); } } for(int i=1;i<=n;i++){ insert(s,i,1,0);insert(i+n,t,1,0); } ans=0;zkw(); if(ans>0) return true; else return false; } int main(){ //freopen("All.in","r",stdin); //freopen("zh.out","w",stdout); 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;double r=10010; double ans1=0; while(abs(r-l)>=eps){ double mid=(l+r)*0.5; if(solve(mid)) ans1=max(ans1,mid),l=mid; else r=mid; } printf("%.6lf\n",r); return 0; }