MCS 并查集#1

Problem A:

原题链接:http://poj.org/problem?id=2236
题目大意:

输入N和d。表示有N台电脑,两个电脑可以直接连接的最大距离为d(这个只输入一次!!!)。电脑的编号为1~N。然后有多次询问。O X表示修复编号为X的电脑。S A B表示询问A和B是否连通(如果A和B连通,B和C连通。那么A和C也连通 )。如果连通输出“SUCCESS”。否则输出“FAIL”

思路:

因为之前输入N台电脑时输入的是坐标。所以用结构体可以很好的解决这个问题。
其余的就和一般的并查集没有什么区别了。按照模板写就可以了

代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int N,d;
int root[1005];
int open[1005];
struct Point
{
    int x;
    int y;
}node[1005];

int find ( int x )
{
    return x == root[x] ? x : find( root[x] );
}

void connect( int x )
{
    int i;
    for( i = 1; i <= N; i++ )
        if( open[i] && i != x )
        {
            int root1,root2;
            root1 = find( x );
            root2 = find( i );
            if( root1 != root2 )
                if( (node[x].x - node[i].x)*(node[x].x - node[i].x) + (node[x].y - node[i].y )*(node[x].y - node[i].y ) <= d*d )
                    root[root2] = root1;
        }
}

int main()
{
    memset( open,0,sizeof(open ));
    scanf("%d %d",&N,&d);
    int i;
    for( i = 1; i <= N; i++ )
    {
        scanf("%d %d",&node[i].x ,&node[i].y );
        root[i] = i;
    }
    char order;
    int x,y;
    while(~scanf("\n%c",&order) )
    {
        if( order == 'O' )
        {
            scanf("%d",&x);
            open[x] = 1;
            connect( x );
        }
        else
        {
            scanf("%d %d",&x,&y);
            x = find( x );
            y = find( y );
            if( x == y )
                printf("SUCCESS\n");
            else
                printf("FAIL\n");
        }
    }
    return 0;
}

Problem B:

原题链接:http://poj.org/problem?id=1611
题目大意:

输入n和m。表示有n个学生(没什么卵用)分成m组。学生的编号是从0~n-1。0号学生每个样例都是默认被标记的。接下来有m行。每行第一个整数K表示的是这个分组有多少个学生。接着输入K个数。如果一个分组中有一人被标记。那么整组的人都被标记。问有多少人被标记

思路:

这道题我自己的思路写成的代码是WA了的
所以这里就不说了。
直接贴套模板代码

代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int n,m;
int root[30005];
int rank[30005];//模板上说这是按秩赋值。好像是一种优化。
int num[30005];

void make_set( int x )
{
    root[x] = x;
    rank[x] = 0;
    num[x] = 1;
}
int find_set( int x )
{
    int r,tmp;
    r = x;
    while( root[r] != r )
    {
        r = root[r];
    }
    while( x != r )
    {
        tmp = root[x];
        root[x] = r;
        x = tmp;
    }
    return x;
}
void union_set( int x, int y )
{
    x = find_set( x );
    y = find_set( y );
    if( x == y )
        return;
    if( rank[x] > rank[y] )
    {
        root[y] = x;
        num[x] += num[y];
    }
    else
    {
        root[x] = y;
        if( rank[y] == rank[x] )
            rank[y]++;
        num[y] += num[x];
    }

}
int main()
{
    while( ~scanf("%d %d",&n,&m) )
    {
        int i,number,x,y,j;
        if( n == 0 && m == 0 )
            break;

        for( i = 0; i < n; i++ )
            make_set( i );

        for( i = 0; i < m; i++ )
        {
            scanf("%d",&number);
            scanf("%d",&x);
            for( j = 1; j < number; j++ )
            {
                scanf("%d",&y);
                union_set( x, y);
                x = y;
            }
        }
        int sum;
        sum = find_set( 0 );
        printf("%d\n",num[sum]);

    }
    return 0;
}

Problem C

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1213
题目大意:

输入一个T(1 <= T <= 25 )。一共有T个测试样例。接着就是M和N。一共M人,N个条信息。简单的说就是。认识的人坐一起。A认识B。B认识C。那么A认识C。问要多少桌子

思路:

看起来就很简单的样子。其实就是那么简单。直接看代码

代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int n,m;
int T;
int root[30005];

void make_set( int x )
{
    root[x] = x;
}
int find_set( int x )
{
    return x == root[x] ? x : find_set( root[x] );
}
void union_set( int x, int y )
{
    x = find_set( x );
    y = find_set( y );
    if( x != y )
        root[y] = x;
}
int main()
{
    scanf("%d",&T);
    while( T-- )
    {
        scanf("%d %d",&n,&m);

        int i,x,y;
        for( i = 1; i<= n; i++ )
            make_set( i );
        for( i = 1; i <= m ; i++ )
        {
            scanf("%d %d",&x,&y);
            union_set( x,y );
        }
        int sum;
        sum = 0;
        for( i = 1; i <= n; i++ )
        {
            if( root[i] == i )
                sum++;
        }
        printf("%d\n",sum);
    }
    return 0;
}

Problem D

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1232
题目大意:

(中文题。略过)

思路:

只要把C的代码改一改就可以A了。直接上代码

代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

int n,m;
int root[30005];

void make_set( int x )
{
    root[x] = x;
}
int find_set( int x )
{
    return x == root[x] ? x : find_set( root[x] );
}
void union_set( int x, int y )
{
    x = find_set( x );
    y = find_set( y );
    if( x != y )
        root[y] = x;
}
int main()
{
    while( ~scanf("%d",&n) )
    {
        if( n == 0 ) break;
        scanf("%d",&m);

        int i,x,y;
        for( i = 1; i<= n; i++ )
            make_set( i );
        for( i = 1; i <= m ; i++ )
        {
            scanf("%d %d",&x,&y);
            union_set( x,y );
        }
        int sum;
        sum = 0;
        for( i = 1; i <= n; i++ )
        {
            if( root[i] == i )
                sum++;
        }
        printf("%d\n",sum-1);
    }
    return 0;
}

Problem E

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1272
题目大意:

(中文题,略过)

思路:

(没有思路QAQ)
介绍二狗的奇门秘术:
判断点的个数和边的条数。如果V(点) - 1 = V(边 )
输出yes,否则输出no
(虽然后来被无情打脸了)

网络大神代码如下:

(大神博客链接:http://www.cnblogs.com/liaoguifa/archive/2012/12/21/2828670.html

#include<stdio.h>
#include<string.h>
#define MAXN 100002
int father[MAXN];
int record[MAXN];

int InitUnion()
{
    int i;
    for(i=0; i<MAXN; ++i)
    {
        father[i] = i;
        record[i] = 0;
    }
}

int find_set(int n)
{// 改成递归的形式<->爆栈 

        while(father[n] != n)
        {
            n = father[n];
        }
        return n;
}

int main()
{
    int x, y, i, a, b, max=-1, flag = 0, cnt = 1, t;
    InitUnion();
    while(scanf("%d%d", &a, &b) == 2 && a != -1 && b != -1)
    {
        if(!a && !b)
        {
            if(cnt == 1)
            printf("Yes\n");
            else
            {
                if(flag) printf("No\n");
                else 
                {
                    for(i=0, t=0; i<=max; ++i)
                    if(record[i] && father[i] == i) t++;
                    if(t > 1) flag = 1;
                    if(!flag) printf("Yes\n");
                    else printf("No\n");
                }
                InitUnion();
                cnt = 1, flag = 0;
                max = -1;
            }
            continue;
        }
        a--, b--;
        cnt = 2;
        max = max > b ? max : b;
        max = max > a ? max : a;
        record[a] = record[b] = 1;
        x = find_set(a), y = find_set(b);
        if(x == y) flag = 1;
        else father[x] = y; 
    }
    return 0;
}

这次我真的不是故意不是注释的!!!!

因为我是有意的。哼!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值