zoukankan      html  css  js  c++  java
  • [BZOJ1370][Baltic2003]Gang团伙 并查集+拆点

    Description

    在某城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足: 1、 我朋友的朋友是我的朋友; 2、 我敌人的敌人是我的朋友; 所有是朋友的人组成一个团伙。告诉你关于这n个人的m条信息,即某两个人是朋友,或者某两个人是敌人,请你编写一个程序,计算出这个城市最多可能有多少个团伙?

    Input

    第1行为n和m,N小于1000,M小于5000; 以下m行,每行为p x y,p的值为0或1,p为0时,表示x和y是朋友,p为1时,表示x和y是敌人。

    Output

    一个整数,表示这n个人最多可能有几个团伙。

    Sample Input

    6
    4
    E 1 4
    F 3 5
    F 4 6
    E 1 2

    Sample Output

    3

    HINT

    {1},{2,4,6},{3,5}

    Solution

    做法:并查集+拆点

    朋友的朋友是我的朋友很好解决,直接并掉两个集合

    关键是敌人的敌人就是我的朋友。

    这个条件用拆点来解决

    假设$x,y$敌对,将$x$和$y+n$这两个集合还有$y$,$x+n$这两个集合并起来就可以了

    为什么要这样呢?

    假设$a,b$为敌,$b,c$为敌,这样就可以把$a,c$并起来了

    另外要注意细节,比如初始化$f[i]$要$for$到$2n$,跑完$m$个关系后要再重新跑一遍

    #include <bits/stdc++.h>
    
    using namespace std ;
    
    #define N 5000
    
    int n , m ;
    int f[ N ] , a[ N ] ;
    
    int find( int x ) {
        if( f[ x ] == x ) {
            return x ;
        }return f[ x ] = find( f[ x ] ) ;
    }
    
    int main() {
        scanf( "%d%d" , &n , &m ) ;
        for( int i = 1 ; i <= 2 * n ; i ++ ) f[ i ] = i ;
        for( int i = 1 ; i <= m ; i ++ ) {
            char ch[ 10 ] ;
            int x , y ;
            scanf( "%s%d%d" , ch , &x , &y ) ;
            if( ch[ 0 ] == 'F' ) f[ find( y ) ] = find( x ) ;
            else {
                f[ find( y + n ) ] = find( x ) ;
                f[ find( x + n ) ] = find( y ) ;
            }
        }
        int ans = 0 ;
        for( int i = 1 ; i <= n ; i ++ ) f[ i ] = find( i ) ;
        sort( f + 1 , f + n + 1 ) ;
        for( int i = 1 ; i <= n ; i ++ ) {
            if( f[ i ] != f[ i - 1 ] ) ans ++ ;
        }
        printf( "%d
    " , ans ) ;
    } 
  • 相关阅读:
    新站发布——寻爱交友网
    博客园居然还在运营
    关于Method类的invoke方法
    创建对象的四种方法
    事务操作
    数据库的并发
    run( )和start( )方法
    JAVA语言的下面几种数组复制方法中,哪个效率最高?
    构造函数问题
    上下转型的调用问题
  • 原文地址:https://www.cnblogs.com/henry-1202/p/BZOJ1370.html
Copyright © 2011-2022 走看看