BZOJ4819: [Sdoi2017]新生舞会(01分数规划)

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上传

洛谷居然卡邻接表,丧心病狂

思路比较简单,裸的洞妖分数规划

枚举一个ans

然后从S向男生连一条流量为1,费用为0的边

从每个女生向T连一条流量为1,费用为0的边

从每个女生向每个男生连一条流量为1,费用为a[i][j]-ans*b[i][j]的边

二分检验

注意边的编号必须从0开始。

注意精度

// luogu-judger-enable-o2
#include<cstdio>
#include<queue>
#include<cstring>
#include<cstdlib>
#define INF 1e8+10
using namespace std;
const int MAXN=201;
const double eps=1e-7;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++)
char buf[1<<20],*p1=buf,*p2=buf;
inline int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
struct node
{
    int u,v,f,nxt;
    double w;
}edge[MAXN*MAXN];
int head[MAXN],num=0;
int N,S,T;
int a[233][233],b[233][233];
double ans=0.0;
inline void add_edge(int x,int y,int z,double k)
{
    edge[num].u=x;
    edge[num].v=y;
    edge[num].f=z;
    edge[num].w=k;
    edge[num].nxt=head[x];
    head[x]=num++;
}
inline void AddEdge(int x,int y,int z,double k)
{
    add_edge(x,y,z,k);
    add_edge(y,x,0,-k);
}
int arrive[MAXN],vis[MAXN],pre[MAXN];
double dis[MAXN];
bool SPFA()
{
    queue<int>q;
    q.push(S);
    for(register int i=S;i<=T;i++) dis[i]=-1e20,arrive[i]=0;
    memset(vis,0,sizeof(vis));
    dis[S]=0;vis[S]=1;
    while(q.size()!=0)
    {
        int p=q.front();q.pop();
        vis[p]=0;arrive[p]=1;
        for(int i=head[p];i!=-1;i=edge[i].nxt)
        {
            if(edge[i].f&&dis[edge[i].v]<dis[p]+edge[i].w)
            {
                dis[edge[i].v]=dis[p]+edge[i].w;
                pre[edge[i].v]=i;
                if(!vis[edge[i].v])
                    q.push(edge[i].v),vis[edge[i].v]=1;
            }
        }
    }
    return arrive[T];
}
int dfs()
{
    int mn=INF;
    int now=T;
    while(pre[now])
    {
        mn=min(mn,edge[pre[now]].f);
        now=edge[pre[now]].u;
    }
    ans+=mn*dis[T];
    now=T;
    while(pre[now])
    {
        edge[pre[now]].f-=mn;
        edge[pre[now]^1].f+=mn;
        now=edge[pre[now]].u;
    }
}
bool check(double val)
{
    memset(pre,0,sizeof(pre));
    memset(head,-1,sizeof(head));
    num=2;
    for(int i=1;i<=N;i++) AddEdge(S,i,1,0);
    for(int i=1;i<=N;i++) AddEdge(i+N,T,1,0);
    for(int i=1;i<=N;i++)    for(int j=1;j<=N;j++) AddEdge(i,j+N,1,a[i][j]-1.0*val*b[i][j]);
    ans=0.0;
    while(SPFA()) 
        dfs();
    if (ans<=0) return 1;
    else return 0;
}
int main()
{
    #ifdef WIN32
    freopen("a.in","r",stdin);
    //freopen("c.out","w",stdout);
    #else
    #endif
    N=read();
    S=0,T=N*2|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,r=10000;
    while(r-l>=eps)
    {
        double mid=(l+r)/2;
        if(check(mid)) r=mid;
        else l=mid;
    }
    printf("%.6lf",l);
    return 0;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ACM算法日常

悬赏题No.1 - 扑克牌

ACM算法日常推出悬赏题啦,悬赏题一般是平时日常听闻的题目,题意简单,结构稍微复杂,并且不知道算法的结果,需要解题者在理解题意的情况下给出合理的解决方案和结果...

9720
来自专栏数据结构与算法

田忌赛马

题目描述 我国历史上有个著名的故事: 那是在2300年以前。齐国的大将军田忌喜欢赛马。他经常和齐王赛马。他和齐王都有三匹马:常规马,上级马,超级马。一共赛三局,...

35890
来自专栏牛客网

渣硕面筋release v1.0(Google已跪)

注:凡是题目需要保密的,都没有写在这里,如有同样要求请通知我修改 校招结束,我选头条 正值十一长假,赶在了小论文截稿前一天投出去了。正好国内的互联网公司校招基本...

523130
来自专栏诸葛青云的专栏

C语言算法设计之奇数魔方阵

将1到n(为奇数)的数字排列在nxn的方阵上,且各行、各列与各对角线的和必须相同,如下所 示:

10700
来自专栏量化投资与机器学习

【量化投资】缠论面面观(附Python源码)

? 来自聚宽:莫邪的救赎的精彩之作 博客连接:https://www.joinquant.com/post/425 因为缠论文章都是博客形式,并无很规范...

1.8K50
来自专栏数据结构与算法

agc016B - Colorful Hats(智商题)

有$n$个人,每个人有一种颜色,第$i$个人说除了我之外有$a_i$种不同的颜色,问是否存在一组合法解

12220
来自专栏数据结构与算法

2018.10.17NOIP模拟赛解题报告

测完发现自己T3挂掉40分因为自己傻逼的在3个if之间加了else,而且T3数据特别水,不打vis标记的spfa都能A。。

9840
来自专栏大数据挖掘DT机器学习

python机器学习入门资料梳理

在python基本语法入门之后,就要准备选一个研究方向了。马上就要进行春季实习招聘了,加油!总结一下python机器学习方面的资料吧。 1、数据处理 1....

30650
来自专栏机器之心

深度 | 你知道《圣经》中的主要角色有哪些吗?三种NLP工具将告诉你答案!

在思考数据科学的时候,我们常常想起数字的统计分析。但是,各种组织机构越来越频繁地生成大量可以被量化分析的非结构文本。一些例子如社交网络评论、产品评价、电子邮件以...

13710
来自专栏纯洁的微笑

设计模式是什么鬼?

9610

扫码关注云+社区

领取腾讯云代金券