zoukankan      html  css  js  c++  java
  • BZOJ4819 新生舞会

    4819: [Sdoi2017]新生舞会

    Time Limit: 10 Sec  Memory Limit: 128 MB

    Description

    学校组织了一次新生舞会,Cathy作为经验丰富的老学姐,负责为同学们安排舞伴。有n个男生和n个女生参加舞会买一个男生和一个女生一起跳舞,互为舞伴。Cathy收集了这些同学之间的关系,比如两个人之前认识没计算得出a[i][j] ,表示第i个男生和第j个女生一起跳舞时他们的喜悦程度。Cathy还需要考虑两个人一起跳舞是否方便,比如身高体重差别会不会太大,计算得出 b[i][j],表示第i个男生和第j个女生一起跳舞时的不协调程度。当然,还需要考虑很多其他问题。Cathy想先用一个程序通过a[i][j]和b[i][j]求出一种方案,再手动对方案进行微调。Cathy找到你,希望你帮她写那个程序。一个方案中有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

    题解

    分数规划 + 网络流

    二分C值,设当前C值为C', 每对人对答案的贡献为( a - b * C' ),费用流使贡献总和最大,为正则说明C'可行。

    使用迭代会使效率更高,每次费用流都是在找一个尽量更优或可行的答案,所以我们把费用流跑出的方案记录下来,作为下一次的C'值。

    每次迭代结束比较上一次的C'与现在跑出来的C'',差的绝对值小于eps则找到最优解,C'的初始值任意。

    代码

    /* Stay hungry, stay foolish. */
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<string>
    #include<map>
    #include<vector>
    #include<set>
    #include<sstream>
    #include<stack>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<climits>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    #include<iomanip>
    #include<bitset>
    #include<complex>
    using namespace std;
    /*
    #define getchar() getc()
    char buf[1<<15],*fs,*ft;
    inline char getc()  {return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin)),fs==ft)?0:*fs++;}
    */
    template <class _T> inline void read(_T &_x) {
        int _t; bool _flag=false;
        while((_t=getchar())!='-'&&(_t<'0'||_t>'9')) ;
        if(_t=='-') _flag=true,_t=getchar(); _x=_t-'0';
        while((_t=getchar())>='0'&&_t<='9') _x=_x*10+_t-'0';
        if(_flag) _x=-_x;
    }
    typedef long long LL;
    const int maxn = 500;
    const int maxm = 100000;
    const double eps = 1e-7;
    struct Edge {
        int v, from, nxt, flow; double cost;
        Edge() {}
        Edge(int a, int b, int c, double d): v(a), nxt(b), flow(c), cost(d) {}
    }e[maxm];
    int fir[maxn], ecnt, pre[maxn], preu[maxn];
    double dis[maxn]; bool vis[maxn];
    inline void addedge(int a, int b, int c, double d) {
        e[++ecnt] = Edge(b, fir[a], c, d), fir[a] = ecnt;
        e[++ecnt] = Edge(a, fir[b], 0, -d), fir[b] = ecnt;
    }
    int n, sink, a[maxn][maxn], b[maxn][maxn];
    inline bool spfa() {
        memset(dis, 0xfe, sizeof (double) * (sink + 1));
        memset(vis, false, sizeof (bool) * (sink + 1));
        double DMIN = dis[0];
        queue<int> q; dis[0] = 0, q.push(0);
        while (!q.empty()) {
            int now = q.front(); q.pop(); vis[now] = false;
            for (int u = fir[now]; u; u = e[u].nxt) if (e[u].flow) {
                if (dis[e[u].v] < dis[now] + e[u].cost) {
                    dis[e[u].v] = dis[now] + e[u].cost;
                    pre[e[u].v] = now, preu[e[u].v] = u;
                    if (!vis[e[u].v]) {
                        vis[e[u].v] = true;
                        q.push(e[u].v);
                    }
                }
            }
        }
        return dis[sink] != DMIN;
    }
    double augment() {
        int now = sink;
        while (now != 0) {
            e[preu[now]].flow -= 1;
            e[preu[now] ^ 1].flow += 1;
            now = pre[now];
        }
        return dis[sink];
    }
    double mcmf() {
        double ret = 0;
        while (spfa()) {
            ret += augment();
        }
        return ret;
    }
    double Run(double ans) {
        ecnt = 1;
        memset(fir, 0, sizeof (int) * (sink + 1));
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                addedge(i, j + n, 1, a[i][j] - ans * b[i][j]);
            }
        }
        for (int i = 1; i <= n; ++i) addedge(0, i, 1, 0);
        for (int i = 1; i <= n; ++i) addedge(n + i, sink, 1, 0);
        mcmf();
        int ansa = 0, ansb = 0;
        for (int i = 1; i <= n; ++i) {
            for (int u = fir[i]; u; u = e[u].nxt) {
                if (e[u].flow == 0 && e[u].v > n && e[u].v < sink) {
                    ansa += a[i][e[u].v - n], ansb += b[i][e[u].v - n];
                }
            }
        }
        return (double)ansa / ansb;
    }
    int main() {
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        read(n); sink = n + n + 1;
        for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j)
            read(a[i][j]);
        for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j)
            read(b[i][j]);
        double prev, ans = 0;
        do {
            prev = ans, ans = Run(ans);
        } while (fabs(ans - prev) > eps);
        printf("%.6lf", ans);
        return 0;
    }
    View Code
  • 相关阅读:
    树莓派4B 多屏 QT程序窗口全屏 QScreen 只能获取1个屏幕
    树莓派4B 微雪7寸触摸屏 双屏 触摸屏校正
    虚拟机 ubuntu18 树莓派4 QT5.14.2 交叉编译
    Qt 指定 so库 运行时路径
    building qtqml requires python
    python django 测试报告 发送邮件
    jmeter XPath Extractor
    python+unittest+HTMLTestRunner生成测试报告
    Genymotion、 uiautomatorviewer、 appium报错
    jmeter forEach控制器
  • 原文地址:https://www.cnblogs.com/akhpl/p/6720544.html
Copyright © 2011-2022 走看看