新生舞会题解

题目

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

题解

首先看到求最小的 \(\large\frac{a'_1 + a'_2 + a'_3+...}{b'_1 + b'_2 + b'_3+...}\) , 很容易想到这道题应该是 \(0/1\) 分数规划。
所以我们直接考虑网络流。
对于一个男生和一个女生, 连一条容量为 ???(随便, 大于等于1就行) , 权值为 \(b_{i, j} * mid - a_{i,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 @ 2022-01-05 16:46  小篪篪  阅读(44)  评论(1)    收藏  举报
Live2D