新生舞会题解

题目

🕊🕊🕊🕊🕊
🕊🕊传🕊🕊
🕊🕊送🕊🕊
🕊🕊门🕊🕊
🕊🕊🕊🕊🕊

题解

首先看到求最小的 a1+a2+a3+...b1+b2+b3+... , 很容易想到这道题应该是 0/1 分数规划。
所以我们直接考虑网络流。
对于一个男生和一个女生, 连一条容量为 ???(随便, 大于等于1就行) , 权值为 bi,jmidai,j 的边, 然后源点向男生连一条权值为 0 , 容量为 1 的边, 表示男生最多可以和其它一名女生匹配。 女生与汇点同理。

代码:

#include <cstdio> #include <algorithm> #include <queue> using namespace std; #define MAXN 400 #define MAXM 160000 template <typename type, typename costtype, int maxn, int maxm, type inf> class SSP { public: type sv[maxm]; private: int H, T; struct node { int ed; node *next; int lo; }se[maxm]; costtype scost[maxm]; node *sn[maxn]; node *si[maxn]; costtype pl[maxn]; int tot; bool vis[maxn]; private: void push_edge (int u, int v, type value, costtype cost) { node *p = &se[tot]; p->ed = v; scost[tot] = cost; sv[tot] = value; p->lo = tot; p->next = sn[u]; sn[u] = p; tot ++; } type dfs (int now, type cap) { vis[now] = 1; if (now == T) { vis[now] = 0; return cap; } type num = 0; for (; si[now]; si[now] = si[now]->next) { if (pl[si[now]->ed] + scost[si[now]->lo] == pl[now] && sv[si[now]->lo] && !vis[si[now]->ed]) { type sum = dfs (si[now]->ed, min (cap - num, sv[si[now]->lo])); sv[si[now]->lo] -= sum; sv[si[now]->lo ^ 1] += sum; num += sum; if (num == cap) { vis[now] = 1; return cap; } } } vis[now] = 0; return num; } pair <type, costtype> dinic (int h, int t, int n) { if (h == t) { return make_pair(inf, inf); } H = h; T = t; queue <int> q; bool bl = 0; for (int i = 1; i <= n; i ++) { pl[i] = inf; vis[i] = 0; } pl[T] = 0; q.push (T); vis[T] = 1; while (!q.empty ()) { int now = q.front (); q.pop (); vis[now] = 0; for (node *i = sn[now]; i; i = i->next) { if (sv[i->lo ^ 1] && pl[i->ed] > pl[now] + scost[i->lo ^ 1]) { pl[i->ed] = pl[now] + scost[i->lo ^ 1]; si[i->ed] = sn[i->ed]; if (i->ed == H) { bl = 1; } if (!vis[i->ed]) { vis[i->ed] = 1; q.push (i->ed); } } } } if (bl) { type cap = dfs (h, inf); costtype cost = cap * pl[H]; return make_pair (cap, cost); } return make_pair (0, 0); } public: void clear () { tot = 0; for (int i = 1; i <= maxn; i ++) { sn[i] = 0; } } void push (int u, int v, type value, costtype cost) { push_edge (u, v, value, cost); push_edge (v, u, 0, -cost); } pair<type, costtype> maxflow (int h, int t, int n){ pair <type, costtype> ans = make_pair (0, 0); while (1) { pair<type, costtype> num = dinic (h, t, n); ans.first += num.first; ans.second += num.second; if (!num.first) { break; } } return ans; } type limited_maxflow (int h, int t, int n, costtype limit) { pair <type, costtype> ans = make_pair (0, 0); while (1) { pair<type, costtype> num = dinic (h, t, n); if (ans.second + num.second > limit) { ans.first += (limit - ans.second) / (num.second / num.first); break; } ans.first += num.first; ans.second += num.second; if (!num.first) { break; } } return ans.first; } }; SSP <long long, double, MAXN + 5, MAXM + 5, 0x3f3f3f3f3f3f3f3f> ssp; double sa[MAXN + 5][MAXN + 5]; double sb[MAXN + 5][MAXN + 5]; int main () { int n; scanf ("%d", &n); for (int i = 1; i <= n; i ++) { for (int j = 1; j <= n; j ++) { scanf ("%lf", &sa[i][j]); } } for (int i = 1; i <= n; i ++) { for (int j = 1; j <= n; j ++) { scanf ("%lf", &sb[i][j]); } } double l = 0, r = 0x3f3f3f3f3f3f3f3f; while (r - l >= 0.00000001) { double mid = (l + r) / 2; ssp.clear(); for (int i = 1; i <= n; i ++) { for (int j = 1; j <= n; j ++) { ssp.push(i, j + n, 1, sb[i][j] * mid - sa[i][j]); } } for (int i = 1; i <= n; i ++) { ssp.push(n * 2 + 1, i, 1, 0); ssp.push (i + n, n * 2 + 2, 1, 0); } if (ssp.maxflow(n * 2 + 1, n * 2 + 2, n * 2 + 2).second < 0) { l = mid; } else { r = mid; } } printf ("%.6lf", l); }
posted @   小篪篪  阅读(33)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
Live2D
欢迎阅读『新生舞会题解』
点击右上角即可分享
微信分享提示