BZOJ 4819 SDOI2017 新生舞会

4819: [Sdoi2017]新生舞会

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

5.357143

HINT

 

Source

鸣谢infinityedge上传

 
二分+费用流
首先二分答案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;
}

  

猜你喜欢

转载自www.cnblogs.com/something-for-nothing/p/9485095.html