Codeforces Round #133 (Div. 2) B. Forming Teams B. Forming Teams 并查集的扩张

http://codeforces.com/problemset/problem/216/B

题意:

有n个人,要求你将他们平均分成两组进行球赛。给出m个敌对关系,每个人最多有两个敌对的人,属于敌对关系的两个人不能分到同一小组里面。输出不能被分到两个小组最少人数。

思路:

和poj的食物链题目类似,这里利用并查集的长度记录关系,每出现一个敌对关系就将他们合并。距离为0表示可以属于同一组,1表示是敌对关系。当出现的两个敌对关系在之前已经确定为同类关系,必然将其剔除。记录剔除的个数,最后检查剔除这些人之后的人数是偶数。

View Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define Min(a,b) (a) > (b)? (b):(a)
#define Max(a,b) (a) > (b)? (a):(b)

#define ll long long
#define inf 0x7f7f7f7f
#define MOD 1073741824
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 1000007
#define N 107
using namespace std;
//freopen("data.in","r",stdin);
int f[N],dep[N];
int num ;

int find(int x){
    if (x != f[x]){
        int tmp = f[x];
        f[x] = find(f[x]);
        dep[x] = (dep[tmp] + dep[x])%2;
    }
    return f[x];
}
void Union(int x,int y){
    int tx = find(x);
    int ty = find(y);
    if (tx != ty){
        f[ty] = tx;
        dep[ty] = (dep[y] + dep[x] + 1)%2;
    }
    else{
        if (iabs(dep[x] - dep[y])%2 == 0) num++;
    }
}
int main(){
   // freopen("data.in","r",stdin);
    int n,m;
    int i;
    int a,b;
    while (~scanf("%d%d",&n,&m)){
        CL(dep,0); num = 0;
        for (i = 1; i <= n; ++i) f[i] = i;
        for (i = 1; i <= m; ++i){
            scanf("%d%d",&a,&b);
            Union(a,b);
        }
        if ((n - num)&1) printf("%d\n",num + 1);
        else printf("%d\n",num);
    }
    return 0;
}
posted @ 2012-10-25 18:18  E_star  阅读(392)  评论(0编辑  收藏  举报