说在前面
并没有什么想说的,但是要保持格式=w=
题目
UOJ#171传送门
BZOJ4405传送门
看题可戳UOJ的传送门
解法
这道题建图真的好巧(反正me不会)
一开始me一直觉得这就是个二分图,然而怎么建图都没办法跑答案
然后去查了题解,得知建图是这样的:
我们让第
个筐对答案的贡献恰好为
就这样建:把一个筐拆成
个点,三个点之间互相连边形成三元环。对于一个球,如果可以放进这个筐,就向这个筐的三个点都连一条边
这样跑最大匹配,显然有
然后因为要输出方案,所以先匹配球,再让筐和筐匹配
就做完了,感觉很厉害…然而并不知道如何才能想到这种建图
下面是代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int T , N , M , E , head[605] , tp ;
int buc[105][3] , ball[305] , id_c , rev[605] ;
struct Path{
int pre , to ;
} p[ 2*(100*300*3*2 + 100*2) + 1000 ] ;
void In( int t1 , int t2 ){
p[++tp] = ( Path ){ head[t1] , t2 } , head[t1] = tp ;
p[++tp] = ( Path ){ head[t2] , t1 } , head[t2] = tp ;
}
int mat[605] , typ[605] , pre[605] ;
int fa[605] , que[605] , fr , ba , ans , tim[605] , tim_c ;
void init(){
id_c = tp = ans = 0 ;
memset( head , 0 , sizeof( head ) ) ;
memset( mat , 0 , sizeof( mat ) ) ;
for( int i = 1 ; i <= N ; i ++ ) ball[i] = ++id_c , rev[id_c] = 0 ;
for( int i = 1 ; i <= M ; i ++ ){
for( int j = 0 ; j < 3 ; j ++ )
buc[i][j] = ++id_c , rev[id_c] = i ;
In( buc[i][0] , buc[i][1] ) , In( buc[i][1] , buc[i][2] ) ;
}
}
int find( int x ){
if( fa[x] == x ) return x ;
return fa[x] = find( fa[x] ) ;
}
int getLca( int u , int v ){
tim_c ++ , u = find( u ) , v = find( v ) ;
while( true ){
if( u ){
if( tim[u] == tim_c ) return u ;
tim[u] = tim_c , u = find( pre[ mat[u] ] ) ;
} swap( u , v ) ;
}
}
void blossom( int u , int v , int lca ){
for( ; find( u ) != lca ; ){
pre[u] = v , fa[u] = fa[ mat[u] ] = lca ;
v = mat[u] , u = pre[v] ;
if( typ[v] == 1 ) typ[v] = 0 , que[++ba] = v ;
}
}
bool BFS( int St ){
for( int i = 1 ; i <= id_c ; i ++ )
typ[i] = -1 , fa[i] = i ;
fr = 1 , typ[St] = 0 , que[ ba = 1 ] = St ;
while( ba >= fr ){
int u = que[fr++] ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( typ[v] == -1 ){
pre[v] = u , typ[v] = 1 ;
if( !mat[v] ){
for( ; v ; u = pre[v] )
mat[v] = u , swap( mat[u] , v ) ;
return true ;
} else typ[ mat[v] ] = 0 , que[++ba] = mat[v] ;
} else if( !typ[v] && find( u ) != find( v ) ){
int Lca = getLca( u , v ) ;
blossom( u , v , Lca ) ;
blossom( v , u , Lca ) ;
}
}
} return false ;
}
void solve(){
for( int i = 1 ; i <= N ; i ++ )
if( !mat[ ball[i] ] ) ans += BFS( ball[i] ) ;
for( int i = 1 ; i <= M ; i ++ )
for( int j = 0 ; j < 3 ; j ++ )
if( !mat[ buc[i][j] ] ) ans += BFS( buc[i][j] ) ;
printf( "%d\n" , ans - N ) ;
for( int i = 1 ; i <= N ; i ++ )
printf( "%d " , rev[ mat[ball[i]] ] ) ;
puts( "" ) ;
}
int main(){
scanf( "%d" , &T ) ;
while( T -- ){
scanf( "%d%d%d" , &N , &M , &E ) , init() ;
for( int i = 1 , u , v ; i <= E ; i ++ ){
scanf( "%d%d" , &u , &v ) ;
for( int j = 0 ; j < 3 ; j ++ )
In( ball[u] , buc[v][j] ) ;
} solve() ;
}
}