【BZOJ4819】【SDOI2017】新生舞会(01分数规划,带权二分图匹配)

90 篇文章 0 订阅
39 篇文章 0 订阅

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值最大。


Solution

01分数规划应该算是个套路了,,
化一下式子:

Cbiai=0 C ∑ b i − ∑ a i = 0

我们二分 C C ,每次将边权赋成bi,j×Cai,j,跑带权二分图匹配即可。
智障选手只会费用流不会KM23333


Code

/************************************************
 * Au: Hany01
 * Date: Apr 9th, 2018
 * Prob: [BZOJ4819][SDOI2017] 新生舞会
 * Email: hany01@foxmail.com
************************************************/

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
#define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
#define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define x first
#define y second
#define pb(a) push_back(a)
#define pf(a) push_front(a)
#define mp(a, b) make_pair(a, b)
#define ALL(a) (a).begin(), (a).end()
#define SZ(a) ((int)(a).size())
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define Mod (1000000007)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define y1 wozenmezhemecaia

template <typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }

inline int read()
{
    register int _, __; register char c_;
    for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
    for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
    return _ * __;
}

const double eps = 1e-7;
inline int dcmp(double x) {
    if (fabs(x) < eps) return 0;
    return x < 0 ? -1 : 1;
}


const int maxn = 105, maxv = 205, maxm = 20203;

int n, e, v[maxm], f[maxm], nex[maxm], beg[maxv], vis[maxv], tot, s, t, a[maxn][maxn], b[maxn][maxn];
double w[maxm], Cost, dis[maxv];


inline void add(int uu, int vv, int ff, double ww, int ty) {
    v[++ e] = vv, f[e] = ff, w[e] = ww, nex[e] = beg[uu], beg[uu] = e;
    if (ty) add(vv, uu, 0, -ww, 0);
}

inline bool BFS()
{
    static queue<int> q;
    For(i, 1, tot) dis[i] = INF, Set(vis, 0);
    dis[s] = 0, vis[s] = 1, q.push(s);
    while (!q.empty())
    {
        register int u = q.front(); q.pop(), vis[u] = 0;
        for (register int i = beg[u]; i; i = nex[i])
            if (f[i] && chkmin(dis[v[i]], dis[u] + w[i]))
                if (!vis[v[i]]) vis[v[i]] = 1, q.push(v[i]);
    }
    return dcmp(dis[t] - INF);
}

int DFS(int u, int flow)
{
    vis[u] = 1;
    if (u == t) return flow;
    register int res = flow, tmp;
    for (register int i = beg[u]; i; i = nex[i])
        if (!vis[v[i]] && f[i] && !dcmp(dis[v[i]] - dis[u] - w[i]))
        {
            tmp = DFS(v[i], min(f[i], res));
            f[i] -= tmp, f[i ^ 1] += tmp, Cost += tmp * w[i];
            if (!(res -= tmp)) return flow;
        }
    return flow - res;
}

inline double MCMF()
{
    Cost = 0.;
    while (BFS())
        do Set(vis, 0), DFS(s, n); while (vis[t]);
    return Cost;
}

inline double check(double c)
{
    e = 1, Set(beg, 0);
    For(i, 1, n) add(s, i, 1, 0, 1), add(i + n, t, 1, 0, 1);
    For(i, 1, n) For(j, 1, n) add(i, j + n, 1, b[i][j] * c - a[i][j], 1);
    return MCMF();
}

int main()
{
#ifdef hany01
    File("bzoj4819");
#endif

    static int Min = INF, Max = 0;

    n = read();
    For(i, 1, n) For(j, 1, n) chkmax(Max, a[i][j] = read());
    For(i, 1, n) For(j, 1, n) chkmin(Min, b[i][j] = read());

    static double l = 1e-4, r = Max * 1. / Min, mid;
    s = n << 1 | 1, t = tot = (n + 1) << 1;
    while (r - l >= eps) {
        mid = (l + r) * .5;
        if (check(mid) < 0) l = mid; else r = mid;
    }
    printf("%.6lf\n", l);

    return 0;
}
//《长恨歌》
//作者:白居易
//汉皇重色思倾国,御宇多年求不得。
//杨家有女初长成,养在深闺人未识。
//天生丽质难自弃,一朝选在君王侧。
//回眸一笑百媚生,六宫粉黛无颜色。
//春寒赐浴华清池,温泉水滑洗凝脂。
//侍儿扶起娇无力,始是新承恩泽时。
//云鬓花颜金步摇,芙蓉帐暖度春宵。
//春宵苦短日高起,从此君王不早朝。
//承欢侍宴无闲暇,春从春游夜专夜。
//后宫佳丽三千人,三千宠爱在一身。
//金屋妆成娇侍夜,玉楼宴罢醉和春。
//姊妹弟兄皆列土,可怜光彩生门户。
//遂令天下父母心,不重生男重生女。
//骊宫高处入青云,仙乐风飘处处闻。
//缓歌谩舞凝丝竹,尽日君王看不足。
//渔阳鼙鼓动地来,惊破霓裳羽衣曲。
//九重城阙烟尘生,千乘万骑西南行。
//翠华摇摇行复止,西出都门百余里。
//六军不发无奈何,宛转蛾眉马前死。
//花钿委地无人收,翠翘金雀玉搔头。
//君王掩面救不得,回看血泪相和流。
//黄埃散漫风萧索,云栈萦纡登剑阁。
//峨嵋山下少人行,旌旗无光日色薄。
//蜀江水碧蜀山青,圣主朝朝暮暮情。
//行宫见月伤心色,夜雨闻铃肠断声。
//天旋地转回龙驭,到此踌躇不能去。
//马嵬坡下泥土中,不见玉颜空死处。
//君臣相顾尽沾衣,东望都门信马归。
//归来池苑皆依旧,太液芙蓉未央柳。
//芙蓉如面柳如眉,对此如何不泪垂。
//春风桃李花开日,秋雨梧桐叶落时。
//西宫南内多秋草,落叶满阶红不扫。
//梨园弟子白发新,椒房阿监青娥老。
//夕殿萤飞思悄然,孤灯挑尽未成眠。
//迟迟钟鼓初长夜,耿耿星河欲曙天。
//鸳鸯瓦冷霜华重,翡翠衾寒谁与共。
//悠悠生死别经年,魂魄不曾来入梦。
//临邛道士鸿都客,能以精诚致魂魄。
//为感君王辗转思,遂教方士殷勤觅。
//排空驭气奔如电,升天入地求之遍。
//上穷碧落下黄泉,两处茫茫皆不见。
//忽闻海上有仙山,山在虚无缥渺间。
//楼阁玲珑五云起,其中绰约多仙子。
//中有一人字太真,雪肤花貌参差是。
//金阙西厢叩玉扃,转教小玉报双成。
//闻道汉家天子使,九华帐里梦魂惊。
//揽衣推枕起徘徊,珠箔银屏迤逦开。
//云鬓半偏新睡觉,花冠不整下堂来。
//风吹仙袂飘飘举,犹似霓裳羽衣舞。
//玉容寂寞泪阑干,梨花一枝春带雨。
//含情凝睇谢君王,一别音容两渺茫。
//昭阳殿里恩爱绝,蓬莱宫中日月长。
//回头下望人寰处,不见长安见尘雾。
//惟将旧物表深情,钿合金钗寄将去。
//钗留一股合一扇,钗擘黄金合分钿。
//但教心似金钿坚,天上人间会相见。
//临别殷勤重寄词,词中有誓两心知。
//七月七日长生殿,夜半无人私语时。
//在天愿作比翼鸟,在地愿为连理枝。
//天长地久有时尽,此恨绵绵无绝期。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值