传送门:【HDU】3861 The King’s Problem
题目分析:首先强连通缩点,因为形成一个环的王国肯定在一条路径中,这样才能保证拆的少。
然后缩点后就是DAG图了,由于题目要求的是最小路径覆盖,那么二分匹配即可。
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <time.h> #include <stdlib.h> using namespace std ; #define REP( i , n ) for ( int i = 0 ; i < n ; ++ i ) #define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i ) #define REPV( i , a , b ) for ( int i = a ; i >= b ; -- i ) #define CLR( a , x ) memset ( a , x , sizeof a ) const int MAXN = 5005 ; const int MAXE = 100005 ; const int MAXQ = 1000005 ; const int INF = 0x3f3f3f3f ; struct Edge { int v , n ; Edge () {} Edge ( int v , int n ) : v ( v ) , n ( n ) {} } ; struct CC { Edge E[MAXE] ; int H[MAXN] , cntE ; int low[MAXN] , dfn[MAXN] , dfs_clock ; int S[MAXN] , top ; int scc[MAXN] , scc_cnt ; int n , m ; void init () { cntE = dfs_clock = scc_cnt = top = 0 ; CLR ( H , -1 ) ; CLR ( scc , 0 ) ; CLR ( dfn , 0 ) ; } void addedge ( int u , int v ) { E[cntE] = Edge ( v , H[u] ) ; H[u] = cntE ++ ; } void Tarjan ( int u ) { low[u] = dfn[u] = ++ dfs_clock ; S[top ++] = u ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( !dfn[v] ) { Tarjan ( v ) ; low[u] = min ( low[u] , low[v] ) ; } else if ( !scc[v] ) low[u] = min ( low[u] , dfn[v] ) ; } if ( low[u] == dfn[u] ) { ++ scc_cnt ; while ( 1 ) { int v = S[-- top] ; scc[v] = scc_cnt ; if ( v == u ) break ; } } } void input () { int u , v ; scanf ( "%d%d" , &n , &m ) ; REP ( i , m ) { scanf ( "%d%d" , &u , &v ) ; addedge ( u , v ) ; } } void find_scc () { REPF ( i , 1 , n ) if ( !dfn[i] ) Tarjan ( i ) ; } void solve () { init () ; input () ; find_scc () ; } } c ; struct Match { Edge E[MAXE] ; int H[MAXN] , cntE ; bool vis[MAXN] ; int Lx[MAXN] , Ly[MAXN] ; int dx[MAXN] , dy[MAXN] ; int Q[MAXQ] , head , tail ; int dis ; int n ; void init () { cntE = 0 ; CLR ( H , -1 ) ; } void addedge ( int u , int v ) { E[cntE] = Edge ( v , H[u] ) ; H[u] = cntE ++ ; } int Hopcroft_Karp () { CLR ( dx , -1 ) ; CLR ( dy , -1 ) ; head = tail = 0 ; dis = INF ; REPF ( i , 1 , n ) if ( Lx[i] == -1 ) { Q[tail ++] = i ; dx[i] = 0 ; } while ( head != tail ) { int u = Q[head ++] ; if ( dx[u] >= dis ) continue ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( dy[v] == -1 ) { dy[v] = dx[u] + 1 ; if ( Ly[v] == -1 ) dis = dy[v] ; else { dx[Ly[v]] = dy[v] + 1 ; Q[tail ++] = Ly[v] ; } } } } return dis != INF ; } int find ( int u ) { for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( dy[v] == dx[u] + 1 && !vis[v] ) { vis[v] = 1 ; if ( ~Ly[v] && dy[v] == dis ) continue ; if ( Ly[v] == -1 || find ( Ly[v] ) ) { Lx[u] = v ; Ly[v] = u ; return 1 ; } } } return 0 ; } int match () { int ans = 0 ; CLR ( Lx , -1 ) ; CLR ( Ly , -1 ) ; while ( Hopcroft_Karp () ) { CLR ( vis , 0 ) ; REPF ( i , 1 , n ) if ( Lx[i] == -1 ) ans += find ( i ) ; } return ans ; } void solve () { init () ; n = c.scc_cnt ; REPF ( u , 1 , c.n ) for ( int i = c.H[u] ; ~i ; i = c.E[i].n ) { int v = c.E[i].v ; if ( c.scc[u] != c.scc[v] ) addedge ( c.scc[u] , c.scc[v] ) ; } int ans = match () ; printf ( "%d\n" , n - ans ) ; } } e ; int main () { int T ; scanf ( "%d" , &T ) ; while ( T -- ) { c.solve () ; e.solve () ; } return 0 ; }