Question: there was a war between the Earth and Mars. Now the Martian will land their paratroopers in an N * m mesh, and we will destroy them. There is a weapon that can instantly destroy all targets in a row or column on the grid. However, the cost of deploying such a weapon in which row or column is different. Therefore, we need to provide the most economical way to make all the paratroopers wiped out. The cost is defined as a deployment scheme that can eliminate all paratroopers and multiply them by the given row and column charges. I hope this day will never come.
Solution: First of all, this question should let countless boys and girls think about the row-and-column matching in binary matching. However, not all rows and columns in this question are equivalent. The weights of the rows and columns are different. Similar to the minimum vertex overwrite in the original problem, this is a minimum vertex overwrite, that is, the use of the minimum vertex weight and the point set so that at least one endpoint of all edges belongs to the vertex set.
The bipartite graph is changed to a stream network with a slight modification. Add the edge from The Source Vertex to each row and each column to the sink vertex. The capacity will be discussed later.
Suppose there is a 3*3 grid, where (1, 2) AND (2, 3) have paratroopers:
Let's take a look at the definition of cut and minimum cut:
Cut: In a graph G (V, E), V is a point set, and E is an edge set. Remove an edge set C in e so that G (v, E-C) is not connected, C is a cut of graph G (V, E, cut the vertex set V of G into two subsets S and T = V-s.
Minimum Cut: In all cut operations of g (V, E), the smallest cut is the sum of edge weights.
For stream networks, we only discuss the s-t cut, that is, the two vertex subsets divided include the Source Vertex s and the sink vertex T.
Assume that the question is about the sum of weights, not the product. Next we will add capacity to the figure above:
R [I] indicates the cost of selecting row I, and C [I] indicates the cost of selecting column I. An infinite edge is connected in the middle, so we consider the following cut:
Because the cut capacity is the capacity of all the forward cut edges, and because the traffic of the entire graph is limited and smaller than the minimum cut capacity, it is impossible to get the infinite edges in the middle. Because every INF edge connects S and T, the Left or Right endpoint of each INF edge must be an endpoint of the cut edge, the Rows 1 and 3 in are true. Otherwise, there will be a path from S to T. This ensures that the non-source non-sink endpoint of each cut edge overwrites all INF edges and satisfies the point coverage. Then, the matching row or column can be determined based on the second endpoint of the cut edge, s or T. Therefore, a minimum cut is obviously the best matching method. Note that a bipartite graph with the weight may deploy a weapon larger than the maximum number of matches. The reason is very simple. Although some rows can eliminate multiple targets, the overhead is too large, selecting one column and one column may reduce the cost.
We assume that the sum of vertex weights is used, and the question is the product of vertex weights. As long as a logarithm is obtained for each vertex right, the multiplication is changed to addition, and then the power is obtained again.
The Code is as follows:
View code
# Include <cstdlib> # include <cstdio> # include <cstring> # include <cmath> # include <iostream> # include <algorithm> using namespace STD; int n, m, l; // The M * n matrix defined in the original question. Change it to N * mconst int Ss = 105, TT = 106; const double INF = 1e9; const double EPS = 1e-8; double RF [55], CF [55]; struct edge {double C; // A Real-number traffic int V, next ;}; edge e [10000]; int idx, head [110], LV [110]; int front, tail, que [110]; void insert (int A, int B, double C) {// printf ("A = % d, B = % d, c = % F \ n", A, B, C ); E [idx]. V = B, E [idx]. C = C; E [idx]. next = head [a]; head [a] = idx ++;} bool sign (Double X) {If (x> EPS) return 1; else if (x <-EPS) Return-1; else return 0;} bool BFS () {front = tail = 0; memset (LV, 0xff, sizeof (LV )); LV [ss] = 0; que [tail ++] = SS; while (front <tail) {int u = que [Front ++]; for (INT I = head [u]; I! =-1; I = E [I]. Next) {int v = E [I]. V; If (! (~ LV [v]) & sign (E [I]. c)> 0) {LV [v] = lv [u] + 1; if (V = TT) return true; que [tail ++] = V ;}}} return false;} double DFS (int u, double sup) {If (u = TT) return sup; double TF = 0, F; for (INT I = head [u]; I! =-1; I = E [I]. next) {int v = E [I]. v; If (LV [u] + 1 = lv [v] & sign (E [I]. c)> 0 & sign (F = DFS (v, min (E [I]. c, sup-tf)> 0) {TF + = f; E [I]. c-= F, E [I ^ 1]. c + = f; If (sign (sup-tf) = 0) return sup;} If (sign (TF) = 0) LV [u] =-1; return TF;} double dinic () {double ret = 0; while (BFS () {RET + = DFS (SS, INF );} // printf ("ret = % F \ n", RET); return ret;} int main () {int t; scanf ("% d", & T ); while (t --) {idx = 0; memset (Head, 0xff, sizeof (head); scanf ("% d", & N, & M, & L); For (INT I = 1; I <= N; ++ I) {scanf ("% lf", & RF [I]); // The compiler must read the double type lf, and the output must use f ...... RF [I] = Log (RF [I]); insert (SS, I, RF [I]); insert (I, SS, 0 ); // because the cost is defined by multiplication, it can be added after being converted to the logarithm} For (INT I = 1; I <= m; ++ I) {scanf ("% lf", & CF [I]); cf [I] = Log (CF [I]); insert (I + 50, TT, cf [I]); insert (TT, I + 50, 0);} int A, B; For (INT I = 0; I <L; ++ I) {scanf ("% d", & A, & B); insert (a, 50 + B, INF); insert (50 + B, A, 0 );} printf ("%. 4f \ n ", exp (dinic ();} return 0 ;}