新生舞会题解
题目
题解
首先看到求最小的 a′1+a′2+a′3+...b′1+b′2+b′3+... , 很容易想到这道题应该是 0/1 分数规划。
所以我们直接考虑网络流。
对于一个男生和一个女生, 连一条容量为 ???(随便, 大于等于1就行) , 权值为 bi,j∗mid−ai,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);
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战