现在的位置: 首页 > 综合 > 正文

【POJ】3723 Conscription 最小生成树

2017年10月15日 ⁄ 综合 ⁄ 共 1262字 ⁄ 字号 评论关闭

传送门:【POJ】3723 Conscription

题目分析:由于一个连通块从哪个节点开始选择最后的花费都是一样的,所以可以成功转化成最小生成树问题。其实本题就是最小生成树的变种——最大生成树,倒过来加边然后和减去总花费就好了。然后我竟然特意设了一个编号为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 ;
}

抱歉!评论已关闭.