题目分析:由于一个连通块从哪个节点开始选择最后的花费都是一样的,所以可以成功转化成最小生成树问题。其实本题就是最小生成树的变种——最大生成树,倒过来加边然后和减去总花费就好了。然后我竟然特意设了一个编号为0的节点,然后对所有的节点建边10000,然后其他的边变成10000-c,最后跑最小生成树就好了。。。看了别人的代码顿时觉得自己真是奇葩。。。简单的题目都想复杂了。。唉唉唉唉唉唉= =
代码如下:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
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 clear( a , x ) memset ( a , x , sizeof a )
typedef long long LL ;
const int MAXN = 20005 ;
const int MAXE = 70005 ;
const int oo = 0x3f3f3f3f ;
struct Line {
int x , y , c ;
Line () {}
Line ( int x , int y , int c ) : x ( x ) , y ( y ) , c ( c ) {}
void input () {
scanf ( "%d%d%d" , &x , &y , &c ) ;
}
bool operator < ( const Line &a ) const {
return c < a.c ;
}
} ;
struct MST {
Line line[MAXE] ;
int p[MAXN] ;
int N , M , NV , NE ;
int find ( int x ) {
return p[x] == x ? x : ( p[x] = find ( p[x] ) ) ;
}
void kruskal () {
int ans = 0 , cnt = 1 ;
sort ( line , line + NE ) ;
REPF ( i , 0 , NV )
p[i] = i ;
REP ( i , NE ) {
int x = find ( line[i].x ) ;
int y = find ( line[i].y ) ;
if ( x != y ) {
ans += line[i].c ;
p[x] = y ;
if ( NV == ( ++ cnt ) )
break ;
}
}
printf ( "%d\n" , ans ) ;
}
void input () {
scanf ( "%d%d%d" , &N , &M , &NE ) ;
NV = N + M + 1 ;
REP ( i , NE ) {
line[i].input () ;
line[i].c = 10000 - line[i].c ;
line[i].y += N ;
}
REPF ( i , 1 , N )
line[NE ++] = Line ( 0 , i , 10000 ) ;
REPF ( i , 1 , M )
line[NE ++] = Line ( 0 , i + N , 10000 ) ;
}
void solve () {
input () ;
kruskal () ;
}
} ;
MST z ;
int main () {
int T ;
scanf ( "%d" , &T ) ;
while ( T -- )
z.solve () ;
return 0 ;
}