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

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1029  Solved: 528
[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上传

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

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

枚举一个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;
}

原文地址:https://www.cnblogs.com/zwfymqz/p/8503229.html

时间: 2024-10-15 06:30:20

BZOJ4819: [Sdoi2017]新生舞会(01分数规划)的相关文章

[BZOJ4819][SDOI2017]新生舞会

[BZOJ4819][SDOI2017]新生舞会 bzoj luogu 题意 有\(n\)个男孩子和\(n\)个女孩子.他们之间要两两结伴跳舞. 已知第\(i\)个男孩子和第\(j\)个女孩子结伴跳舞会有两个参数\(a_{i,j}\)和\(b_{i,j}\). 现在要求一个安排方案使得\(a_{i,j}\)的总和除以\(b_{i,j}\)的总和的商尽量大. 形式化地,就是求一个长度为\(n\)的排列\(\{p_i\}\),最大化\(L=\frac{\sum_{i=1}^{n}a_{i,p_i}}

[Sdoi2017]新生舞会

[Sdoi2017]新生舞会 http://www.lydsy.com/JudgeOnline/problem.php?id=4819 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 学校组织了一次新生舞会,Cathy作为经验丰富的老学姐,负责为同学们安排舞伴.有n个男生和n个女生参加舞会 买一个男生和一个女生一起跳舞,互为舞伴.Cathy收集了这些同学之间的关系,比如两个人之前认识没计算

01分数规划模板

/* 01分数规划模板(Dinkelbach) 01分数规划就是把 sum(a)/sum(b)转换成 f(x)=sum(a)-ans*sum(b); 当f(x)取到0时,ans取到了最大(小)值 poj 2976 两个长度为n的数组a,b 可以除去m个,怎样选择才能使剩下的 sum(a)/sum(b)的百分数最大 */ int n,m; struct Node{ int a,b; double v; ///用于排序筛选较大的值(题目要求极大值 bool operator<(const Node&am

poj3621 Sightseeing Cows --- 01分数规划

典型的求最优比例环问题 参考资料: http://blog.csdn.net/hhaile/article/details/8883652 此题中,给出每个点和每条边的权值,求一个环使 ans=∑点权/∑边权 最大. 因为题目要求一个环,而且必然是首尾相接的一个我们理解的纯粹的环,不可能是其他样子的环, 所以我们可以把一条边和指向的点看做整体处理. 上面方程可以化为:ans×e[i]-p[i]=0 以它为边权二分答案,spfa求负环,有负环则该ans可行,增大下界. 若一直不可行,则无解. #i

【Earthquake, 2001 Open 】 0-1 分数规划

71  奶牛施工队一场地震把约翰家园摧毁了,坚强的约翰决心重建家园.约翰已经修复了 N 个牧场,他需要再修复一些道路把它们连接起来.碰巧的是,奶牛们最近也成立了一个工程队,专门从事道路修复.而然,奶牛们很有经济头脑,如果无利可图,它们是不会干的.约翰和奶牛达成了协议,约翰向奶牛支付 F 元,奶牛负责修路,但不必修复所有道路,只要确保所有牧场连通即可.可供奶牛选择修复的道路有 M 条,第 i 条道路连接第 Ui 个牧场和第 Vi 个牧场,修复需要 Ti 分钟,支出成本为 Ci.保证连通所有牧场的道

编程之美第一篇 01分数规划

01分数规划 01分数规划问题其实就是解决单价之类的问题,假设给你n个物品,让你找出选k个物品的最大单价:例如南阳oj:Yougth的最大化:解决这类问题可以用二分查找,这类问题跟二分极大化最小值,极小化最大值有一些相似的地方,均是从结果出发,来进行二分查找:例如上面南阳那道题,可以转化一下: 由于v/w=单价:所以v=w*单价:即v-w*单价=0:有了这个关系,我们马上可以想到二分来查找这个值: 那么我们可以定义一个count数组来记录v-w*单价的值:由于选k个只需要把count从大到小排下

zoj 2676 Network Wars(最小割,01分数规划)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2676 大致题意:给出一个带权无向图,每条边有一个边权wi,求将S和T分开的一个割边集C,使得该割边集的平均边权最小,即最小化∑wi / |C| . 详见amber关于最小割模型的论文 思路:amber论文中详细讲解了如何转化成函数及建图,值得注意的是当边被重新赋权后,对于wi < 0 的边权,该边必然在最小割中,不必再建边,直接加入最大流中即可,因为求最小割时边权都为正值

zoj2676--Network Wars(0-1分数规划+最小割)

zoj2676:题目链接 题目大意:有一个n个点的网络,其中有m条光缆(所有的点都被连接,任意两个点之间最多有一条,不存在连接自身的),每条光缆有一定的价值,网络中1为起点,n为终点,现在要求找出一些光缆能分割开1到n,使它们不能相互通信,并且要求花费的和除以光缆数的值最小.输出选择的光缆的编号. 从问题中可以看出一定是0-1分数规划的题目,假设选出光缆的集合M,M为原图的一个割,光缆si∈M,价值为ci,数量k = 1 ,可以推出g(x) = min( ∑c - x*∑k ),因为si是割中的

[POJ 2728]Desert King(0-1分数规划/最优比率生成树)

Description David the Great has just become the king of a desert country. To win the respect of his people, he decided to build channels all over his country to bring water to every village. Villages which are connected to his capital village will be