# LOJ6002 [Network Flow Question 24-3] Drop Small Path Coverage Bipartite Drop Large Matching

Keywords: network

# Everyone is strong enough to share their support.

Topic:

_Given a directed graph G=(V,E).Set P to be a set of G's simple paths with disjoint vertices.If each vertex in V happens to be on a path of P, P is said to be a path coverage of G.A path in P can start from any vertex of V and have an arbitrary length, especially 0.The minimum path coverage of G is the path coverage of G with the least number of paths.

Questions:

_is transformed into a problem of large drop matching in a bipartite graph, where each point u is split into a point u x on the left and a point uy on the right, and then (u x, vy) is connected to an arc with a flow rate of x(x <[1,+ <)] for an edge (u,v).

_Finds its drop size match and subtracts the total number of points to get the minimum path coverage.

Prove:

We think that at first each point is a separate path, with a total of n disjoint paths.Each time we find a matching edge in the bipartite graph, it is equivalent to synthesizing a path from two paths, which is equivalent to reducing the number of paths by one.So if several matching edges are found, the number of paths will be reduced.So Minimum Path Coverage = Number of nodes in the original map - Maximum number of matches in the new map.

If you want to output the solution, just look for the edge with 0 traffic in it...See code for details

```# include <bits/stdc++.h>

# define N 2010

class Network  {
private :
struct edge  {
int to, w, nxt ;
edge ( ) {        }
edge ( int to, int w, int nxt ) : to ( to ), w ( w ), nxt ( nxt ) {        }
} g [60010 << 1] ;

int head [N], cur [N], ecnt ;
int S, T , dep [N] ;

inline int dfs ( int u, int a )  {
if ( u == T || ! a )  return a ;
int flow = 0, v, f ;
for ( int& i = cur [u] ; i ; i = g [i].nxt )  {
v = g [i].to ;
if ( dep [v] == dep [u] + 1 )  {
f = dfs ( v, std :: min ( g [i].w, a - flow ) ) ;
g [i].w -= f, g [i ^ 1].w += f ;
flow += f ;
if ( a == flow )  return a ;
}
}
if ( ! flow )  dep [u] = -1 ;
return flow ;
}

inline bool bfs ( int S, int T )  {
static std :: queue < int > q ;
memset ( dep, 0, sizeof ( int ) * ( T + 1 ) ) ;
dep [S] = 1 ;
q.push ( S ) ;
while ( ! q.empty ( ) )  {
int u = q.front ( ) ;  q.pop ( ) ;
for ( int i = head [u] ; i ; i = g [i].nxt )  {
int& v = g [i].to ;
if ( g [i].w &&  ! dep [v] )  {
dep [v] = dep [u] + 1 ;
q.push ( v ) ;
}
}
}
return dep [T] ;
}
public :
Network ( )  {    ecnt = 1 ; }

inline void add_edge ( int u, int v, int w )  {
g [++ ecnt] = edge ( v, w, head [u] ) ;     head [u] = ecnt ;
g [++ ecnt] = edge ( u, 0, head [v] ) ;     head [v] = ecnt ;
}

inline int dinic ( int S, int T )  {
this -> S = S, this -> T = T ;
int rt = 0 ;
while ( bfs ( S, T ) )    {
memcpy ( cur, head, sizeof ( int ) * ( T + 1 ) ) ;
rt += dfs ( S, 0x3f3f3f3f ) ;
}
return rt ;
}

void display ( int n, int S, int T )  {

int ans = n - dinic ( S, T ) ;

static std :: bitset < N > vis ;
vis.reset ( ) ;
for ( int i = 1 ; i <= n ; ++ i )
if ( ! vis.test ( i ) )  {
int curr = i ;
for ( bool found = 0 ; ; found = 0 )  {
printf ( "%d ", curr ) ;
vis.set ( curr ) ;
for ( int i = head [curr] ; i ; i = g [i].nxt )  {
int& v = g [i].to ;
if ( g [i].w == 0 && v > n && v <= 2 * n )  {
curr = v - n ;
found = 1 ;
break ;
}
}
if ( found == 0 )  {
puts ( "" ) ;
break ;
}
}
}

printf ( "%d\n", ans ) ;
}
} Lazer ;

int main ( )  {
int n, m ;
scanf ( "%d%d", & n, & m ) ;

const int S = n * 2 + 1, T = n * 2 + 2 ;

for ( int i = 1 ; i <= n ; ++ i )  {
Lazer.add_edge ( S, i, 1 ) ;
Lazer.add_edge ( i + n, T, 1 ) ;
}

while ( m -- )  {
static int u, v ;
scanf ( "%d%d", & u, & v ) ;
Lazer.add_edge ( u, v + n, 1 ) ;
}

Lazer.display ( n, S, T ) ;
return 0 ;
}```

Posted by cmw on Tue, 07 Jul 2020 08:20:28 -0700