zoukankan      html  css  js  c++  java
  • LibreOJ 2003. 「SDOI2017」新生舞会 基础01分数规划 最大权匹配

    #2003. 「SDOI2017」新生舞会

    内存限制:256 MiB时间限制:1500 ms标准输入输出
    题目类型:传统评测方式:文本比较
    上传者: 匿名

    题目描述

    学校组织了一次新生舞会,Cathy 作为经验丰富的老学姐,负责为同学们安排舞伴。

    有 n nn 个男生和 n nn 个女生参加舞会,一个男生和一个女生一起跳舞,互为舞伴。
    Cathy 收集了这些同学之间的关系,比如两个人之前是否认识,计算得出 ai,j a_{i, j}ai,j​​,表示第 i ii 个男生和第 j jj 个女生一起跳舞时他们喜悦程度。
    Cathy 还需要考虑两个人一起跳舞是否方便,比如身高体重差别会不会太大,计算得出 bi,j b_{i, j}bi,j​​ 表示第 i ii 个男生和第 j jj 个女生一起跳舞时的不协调裎度。

    当然,还需要考虑很多其他间题。

    Cathy 想先用一个程序通过 ai,j a_{i, j}ai,j​​ 和 bi,j b_{i, j}bi,j​​ 求出一种方案,再手动对方案进行微调。
    Cathy 找到你,希望你帮她写那个程序。

    一个方案中有 n nn 对舞伴,假设每对舞伴的喜悦程度分别是 a1′,a2′,…,an′ a'_1, a'_2, ldots, a'_na1​​,a2​​,,an​​,假设每对舞伴不协调程度分别是 b1′,b2′,…,bn′ b'_1, b'_2, ldots, b'_nb1​​,b2​​,,bn​​。令

    C=a1′+a2′+⋯+an′b1′+b2′+⋯+bn′ C = frac{a'_1 + a'_2 + cdots + a'_n}{b'_1 + b'_2 + cdots + b'_n}C=b1​​+b2​​++bn​​a1​​+a2​​++an​​​​

    Cathy 希望 C 值最大。

    输入格式

    第一行一个整数 n nn。
    接下来 n nn 行,每行 n nn 个正整数,第 i ii 行第 j jj 个数表示 ai,j a_{i, j}ai,j​​。
    接下来 n nn 行,每行 n nn 个正整数,第 i ii 行第 j jj 个数表示 bi,j b_{i, j}bi,j​​。

    输出格式

    一行一个数,表示 C CC 的最大值。四舍五入保留六位小数,选手输出的小数需要与标准输出相等。

    样例

    样例输入

    3
    19 17 16
    25 24 23
    35 36 31
    9 5 6
    3 4 2
    7 8 9

    样例输出

    5.357143

    数据范围与提示对于 10% 10\%10% 的数据,1≤n≤5 1 leq n leq 51n5;

    对于 40% 40\%40% 的数据,1≤n≤18 1 leq n leq 181n18;
    另外存在 20% 20\%20% 的数据,bi,j=1 b_{i, j} = 1bi,j​​=1;
    对于 100% 100\%100% 的数据,1≤n≤100,1≤ai,j≤104,1≤bi,j≤104 1 leq n leq 100, 1 leq a_{i, j} leq 10 ^ 4,1 leq b_{i, j} leq 10 ^ 41n100,1ai,j​​104​​,1bi,j​​104​​。

    传送一篇来自苣苣的博客:01分数规划总结

    感觉01分数规划就是先二分答案,然后再求最值。

    题目链接:https://loj.ac/problem/2003

    题意:选出n对舞伴,使得价值和/代价和最大。

    思路:基础01分数规划+最大权匹配(可以使用最小费用流求解,先对费用取负数,最后答案再取负数)

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<set>
    #include<queue>
    #include<stack>
    #include<map>
    #include<vector>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> P;
    const int maxn=200,maxm=1e5+100,inf=0x3f3f3f3f,mod=1e9+7;
    const ll INF=1e18+7;
    const double eps=1e-10;
    int a[maxn][maxn],b[maxn][maxn];
    struct edge
    {
        int from,to;
        int c;
        int a,b;
    };
    vector<edge>es;
    vector<int>G[maxn];
    double dist[maxn];
    int pre[maxn];
    void addedge(int u,int v,int c,int a,int b)
    {
        es.push_back((edge)
        {
            u,v,c,a,b
        });
        es.push_back((edge)
        {
            v,u,0,-a,-b
        });
        int x=es.size();
        G[u].push_back(x-2);
        G[v].push_back(x-1);
    }
    bool SPFA(int s,int t,double mid)
    {
        static std::queue<int> q;
        static bool inq[maxn];
        for(int i=0; i<maxn; i++) dist[i]=1.0*inf,inq[i]=false;
        pre[s]=-1;
        dist[s]=0.0;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            inq[u]=false;
            for(int i=0; i<G[u].size(); i++)
            {
                edge e=es[G[u][i]];
                double d=0.0;
                if(e.a&&e.b) d=1.0*e.a-mid*e.b;
                if(e.c&&dist[e.to]>dist[u]-d)
                {
                    pre[e.to]=G[u][i];
                    dist[e.to]=dist[u]-d;
                    if(!inq[e.to]) q.push(e.to),inq[e.to]=true;
                }
            }
        }
        return fabs(inf-dist[t])>eps;
    }
    double dinic(int s,int t,int f,double mid)
    {
        int flow=0;
        double cost=0.0;
        while(SPFA(s,t,mid))
        {
            int d=f;
            for(int i=t; i!=s; i=es[pre[i]].from)
                d=min(d,es[pre[i]].c);
            f-=d;
            flow+=d,cost+=d*dist[t];
            for(int i=t; i!=s; i=es[pre[i]].from)
            {
                es[pre[i]].c-=d;
                es[pre[i]^1].c+=d;
            }
            if(f<=0) break;
        }
        for(int i=0; i<es.size(); i+=2) es[i].c=1,es[i+1].c=0;
        //cout<<-1*cost<<" ******"<<endl<<endl;
        return -1*cost;
    }
    bool check(double mid,int s,int t,int n)
    {
        return dinic(s,t,n,mid)>=eps?true:false;
    }
    int main()
    {
        int n,m;
        scanf("%d",&n);
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
                scanf("%d",&a[i][j]);
        }
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
                scanf("%d",&b[i][j]);
        }
        int s=0,t=2*n+1;
        for(int i=1; i<=n; i++) addedge(s,i,1,0,0);
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
                addedge(i,j+n,1,a[i][j],b[i][j]);
        }
        for(int i=1; i<=n; i++) addedge(i+n,t,1,0,0);
        double l=0.0,r=1000000000.0;
        double ans=0.0;
        while((r-l)>eps)
        {
            double mid=(l+r)/2;
            //printf("%.8f %.8f %.8f
    ",l,r,mid);
            if(check(mid,s,t,n)) l=mid,ans=l;
            else r=mid;
        }
        printf("%.6f
    ",ans);
        return 0;
    }
    基础01分数规划+最大权匹配
  • 相关阅读:
    ADO.NET 根据实体类自动生成添加修改语句仅限Oracle使用
    C# 实体对象作为参数统一去除空格
    jQuery 前端复选框 全选 反选 下拉菜单联动
    C# 后台服务器端 Get 请求函数封装
    服务器404错误页面
    vue 封装公用函数
    Vue 生命周期
    Oracle 查看表结构
    ubuntu源配置
    外观(Facade)模式
  • 原文地址:https://www.cnblogs.com/GeekZRF/p/7347185.html
Copyright © 2011-2022 走看看