n × m 網格,L 個傘兵坐標 (x, y)。i 行成本 r[i],第 j 列成本 c[j]。log(a × b × c) = log a + log b + log c → **將乘積最小化轉為加權和最小化**。
邊權設為 log(r[i])、log(c[j]),跑最小割,最後 exp(min_cut) 還原答案。
S,匯點 T。1..n,邊 S → row_i 容量 log(r[i])。1..m,邊 col_j → T 容量 log(c[j])。(x, y) → 邊 row_x → col_y 容量 INF(強制割掉行或列)。log(乘積) 最小。const double INF = 1e100;
struct Edge { int to, next; double cap; };
vector edges;
vector head, level, cur;
void add_edge(int u, int v, double c) {
edges.push_back({v, head[u], c}); head[u] = edges.size()-1;
edges.push_back({u, head[v], 0}); head[v] = edges.size()-1;
}
bool bfs(int S, int T) { /* 建立層次圖 */ }
double dfs(int u, int T, double f) { /* 阻塞流 */ }
double dinic(int S, int T) { /* 主循環 */ }
int main() {
int T; scanf("%d", &T);
while (T--) {
int n, m, q; scanf("%d%d%d", &n, &m, &q);
vector R(n+1), C(m+1);
for (int i=1;i<=n;++i) scanf("%lf", &R[i]);
for (int j=1;j<=m;++j) scanf("%lf", &C[j]);
// 初始化圖
int S = 0, T = n + m + 1;
head.assign(T+1, -1); edges.clear();
// 建邊
for (int i=1;i<=n;++i) if (R[i]>0) add_edge(S, i, log(R[i]));
for (int j=1;j<=m;++j) if (C[j]>0) add_edge(n+j, T, log(C[j]));
for (int k=0;k
double 存儲對數容量,INF = 1e100 足夠大。r[i] 或 c[j] 為 0 時 log(0) = -inf,需特判:成本為 0 的行/列直接加入割集(或設容量極大負數),代碼中略過 <=0 的邊等價於不選擇該行/列,但若成本為 0 應**強制選擇**,需額外處理(如設容量 -1e50)。exp() 可能溢出,題目保證答案在範圍內。≤ 102,邊 ≤ 10000。O(E√V) 極快。