hdu1198—并查集

华电北风吹
天津大学认知计算与应用重点实验室
日期:2015/09/17

原题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=1198
初始一个和矩阵方格数相等的一维数组,矩阵每个下标代表矩阵每个方块,一维数组每个元素的值代表当前节点的父节点。初始时,每个节点都是根节点(父节点是本身)。
这样做的优点:
集合合并的话只需要将两个集合的根节点的其中一个修改为另一个即可。
计算联通分量个数只需要遍历数组,计数根节点个数即可。
C++ code:

#include <iostream>
#include <fstream>
using namespace std;

#include<string.h>

char str[2][9] = { { "ABEGHJK" }, { "ACFGHIK" } };
int f[2505], m, n;
char map[52][52];

int check(int x, int y)
{
    if (x >= 0 && x<m && y >= 0 && y<n)
        return 1;
    return 0;
}

int getFather(int a)
{
    while (a != f[a])
        a = f[a];
    return a;
}

void Union(int a, int b)
{
    int root1 = getFather(a);
    int root2 = getFather(b);
    if (root1 != root2)
    {
        if (root1<root2)
            f[root2] = root1;
        else
            f[root1] = root2;
    }
}

int judge(char c, int flag)
{
    int i;
    for (i = 0; i<7; i++)
    {
        if (str[flag][i] == c)
            return i + 1;
    }
    return 0;
}

void process()
{
    int i, j, dx, dy;
    char c;
    for (i = 0; i <= n*m; i++)
        f[i] = i;
    for (i = 0; i<m; i++)
    {
        for (j = 0; j<n; j++)
        {
            c = map[i][j];
            if (c == 'C' || c == 'D' || c == 'E' || c == 'H'|| c == 'I' || c == 'J' || c == 'K')
            {
                dx = i + 1;
                dy = j;
                if (check(dx, dy))
                {
                    if (judge(map[dx][dy], 0))
                    {
                        Union(i*n + j, dx*n + dy);
                    }
                }
            }
            if (c == 'B' || c == 'D' || c == 'F' || c == 'G'|| c == 'I' || c == 'J' || c == 'K')
            {
                dx = i;
                dy = j + 1;
                if (check(dx, dy))
                {
                    if (judge(map[dx][dy], 1))
                    {
                        Union(i*n + j, dx*n + dy);
                    }
                }
            }
        }
    }
    int result = 0;
    for (i = 0; i<n*m; i++)
        if (f[i] == i)
            result++;
    cout << result << endl;
}
int main()
{
    ifstream in(".\\input.txt");
    cin.rdbuf(in.rdbuf());

    while (cin>>m>>n)
    {
        if (m<0 || n<0)
            break;
        cin.ignore();
        for (int i = 0; i < m; i++)
            cin.getline(map[i], 255);
        process();
    }
    system("pause");
    return 0;
}

python code:

def mainfunc(filename):
    file=open(filename,'r')
    while True:
        line=file.readline().strip('\n')
        if len(line)==0:
            continue
        if line=="-1 -1":
            break
        line=line.split()
        M,N=int(line[0]),int(line[1])
        type=[file.readline().strip('\n') for i in range(M)]
        Func(M,N,type)
    file.close()

def Findroot(leader,i):
    while leader[i]!=i:
        i=leader[i]
    return i

def JudgeVerticalUnion(type,row,col):
    if type[row][col] in 'CDEHIJK':
        if type[row+1][col] in 'ABEGHJK':
            return True
    return False

def JudgeHorizonlUnion(type,row,col):
    if type[row][col] in 'BDFGIJK':
        if type[row][col+1] in 'ACFGHIK':
            return True
    return False

def Union(leader,p1,p2):
    f1=Findroot(leader,p1)
    f2=Findroot(leader,p2)
    if f1<f2:
        leader[f2]=f1
    else:
        leader[f1]=f2

def Func(M,N,type):
    leader=[i for i in range(M*N)]
    for row in range(M):
        for col in range(N):
            if row+1<M:
                if JudgeVerticalUnion(type,row,col):
                    p=row*N+col
                    Union(leader,p,p+N)
            if col+1<N:
                if JudgeHorizonlUnion(type,row,col):
                    p=row*N+col
                    Union(leader,p,p+1)
    result=0
    for i in range(M*N):
        if leader[i]==i:
            result+=1
    print(result)

mainfunc('input.txt')

项目代码下载:
https://github.com/ncepuzhengyi/ProblemSet/tree/master/ProblemSet/hdu1198
参考网址:
http://blog.csdn.net/njdragonfly/article/details/5442761

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值