最小割
建图: 以行和列为点,行列激光枪的安装费用为边。 源点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;
}
浙公网安备 33010602011771号