题目链接

最小割

建图: 以行和列为点,行列激光枪的安装费用为边。 源点s与每一个行连一条边,每一个列和汇点连一条边,根据伞兵的坐标(x, y),从x向y连一条边,边的容量为INF。

因为题目要求的是费用的乘积,可以通过下面的技巧来算。

因为 \(2^x\) * \(2^y\) = \(2^{x+y}\)
假设 a = \(2^x\), b = \(2^y\)
那么 a*b = \(2^{log_2 a+log_2 b}\)

只要求出最大的 \(log_2 a+log_2 b\) 就能求出最大的a*b

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>

using namespace std;

const int Maxn = 200+10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-6;

struct Edge {
	int v, next;
	double cap, flow;
} edge[Maxn*Maxn*2];

int h[Maxn], edge_cnt, indx[Maxn], deep[Maxn];

void add(int u, int v, double c) {
	edge[edge_cnt].v = v;
	edge[edge_cnt].cap = c;
	edge[edge_cnt].flow = 0;
	edge[edge_cnt].next = h[u];
	h[u] = edge_cnt++;
	
	edge[edge_cnt].v = u;
	edge[edge_cnt].cap = 0;
	edge[edge_cnt].flow = 0;
	edge[edge_cnt].next = h[v];
	h[v] = edge_cnt++;
}

bool bfs(int s, int t) {
	memset(deep, 0, sizeof(deep));
	deep[s] = 1; queue<int> qu;
	qu.push(s);
	
	while(!qu.empty()) {
		int u = qu.front(); qu.pop();
		for(int i = h[u]; i != -2; i = edge[i].next) {
			Edge &e = edge[i];
			if(deep[e.v] == 0 && (fabs(e.cap-e.flow) > eps && e.cap > e.flow)) {
				deep[e.v] = deep[u]+1;
				qu.push(e.v);
			}
		}
	}
	if(deep[t] > 0) return true;
	else return false;
}

double dfs(int u, int t, double a) {
	if(u == t || a < eps) return a;
	double flow = 0, f;
	if(indx[u] == -1) indx[u] = h[u];
	for(int &i = indx[u]; i != -2; i = edge[i].next) {
		Edge &e = edge[i];
		if(deep[e.v] == deep[u]+1) {
			f = dfs(e.v, t, min(a, e.cap-e.flow));
			if(f > eps) {
				e.flow += f;
				edge[i^1].flow -= f;
				flow += f;
				a -= f;
				if(a < eps) break;
			}
		}
	}
	return flow;
} 

void dinic(int s, int t) {
	double ans = 0;
	while(bfs(s, t)) {
		memset(indx, -1, sizeof(indx));
		ans += dfs(s, t, INF);
	}
	printf("%.4f\n", (double)pow(2.0, ans));
}

int main(void)
{
	int n, m, k, T;
	scanf("%d", &T);
	while (T--) {
		scanf("%d%d%d", &n, &m, &k);
		for(int i = 0; i <= n+m+1; ++i) h[i] = -2;
		edge_cnt = 0;
		double val;
		for(int i = 1; i <= n; ++i) {
			scanf("%lf", &val);
			add(0, i, log(val)/log(2));
		}
		for(int i = n+1; i <= m+n; ++i) {
			scanf("%lf", &val);
			add(i, n+m+1, log(val)/log(2));
		}
		int x, y;
		for(int i = 0; i < k; ++i) {
			scanf("%d%d", &x, &y);
			add(x, y+n, INF);
		}
		dinic(0, n+m+1);
	}
	return 0;
 }