poj 3723 Conscription(Kruskal + 并查集)

题意:windy要组建一支军队,召集了N个女孩和M个男孩,每个人要付10000RMB,但是如果一个女孩和一个男孩有关系d的,且已经付给了其中一个人的钱,那么就可以付给另一个人10000-d元,求windy最少要付多少钱。

解题过程:写了一个prim的最小生成树才发现原来整个图不是连通的,所以想到用Kruskal,刚开始的时候val中存的是10000-d,然后求最小生成树,但是最后求有几棵树的时候不是很好计算,改了一下f[x]、f[y]的赋值规则还是不行,然后看到有人说求最大生成树,然后就改了一下条件就AC了。

代码:

View Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <math.h>
#define  N 50005
#define  M 20005
using namespace std ;

struct node
{
    int s , e ;
    int val ;
}p[N] ;

int f[M] , n , m , r , num ;

int cmp ( const node a , const node b )
{
    return a.val > b.val ;
}

void init()
{
    int i ;
    for ( i = 0 ; i <=  n + m ; i++ )
    f[i] = i ;
}

void add ( int x , int y , int z )
{
    p[num].s = x ;
    p[num].e = y ;
    p[num].val = z ;
    num++ ;
}

int find ( int x )
{
    if ( f[x] != x )
    f[x] = find ( f[x] ) ;
    return f[x] ;
}

int main()
{
    int cas , i , x , y , z ;

    //freopen( "input.txt" , "r" , stdin) ;
    scanf ( "%d" , &cas ) ;
    while ( cas-- )
    {
        scanf ( "%d%d%d" , &n , &m , &r ) ;
        num = 0 ;
        for ( i = 1 ; i <= r ; i++ )
        {
            scanf ( "%d%d%d" , &x , &y , &z ) ;
            add ( x + 1 , y + n + 1 , z );
        }

        sort ( p , p + num , cmp ) ;
        init() ;
        int sum = ( n + m ) * 10000 ;
        for ( i = 0 ; i < num ; i++ )
        {
            x = find ( p[i].s ) ;
            y = find ( p[i].e ) ;
            if ( x != y )
            {
                sum -= p[i].val ;
                f[x] = y ;
            }
        }
        for ( i = 1 ; i <= n + m ; i++ )
        cout<<f[i]<<" ";
        cout<<endl ;

        /*sort ( f , f + n + m + 1 ) ;
        x = 1 ;
        for ( i = 2 ; i <= n + m ; i++ )
        if ( f[i] != f[i-1] )
        x++ ;*/

        printf ( "%d\n" , sum ) ;
    }
    return 0 ;
}
原文地址:https://www.cnblogs.com/misty1/p/2739066.html