• 【并查集】hdu 1198 Farm Irrigation


    题目描述:

    http://acm.hdu.edu.cn/showproblem.php?pid=1198

     

    中文大意:

    农田是一个矩形,被分成了若干个小正方形。

    小正方形区域内,将会铺设上水管,用来灌溉农田。

    现在,想知道,至少需要多少个泉源,才能将农田全部灌溉。

    已知共有 11 种管道,从 A 到 K 标记。

    水可以沿着管道从一个正方形流到另一个正方形。

    思路:

    尝试将相互流通的小正方形合并到一个集合。

    最终,集合个数即为泉源个数。

     

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    int m,n;
    int maps[50][50];//水管类型 
    int pre[2500];//各节点的所属集 
    int height[2500];//各集合的树高 
    
    //初始化 
    void init(){
        for(int i=0;i<m*n;i++){
            pre[i] = i;
            height[i] = 1;
        }
    } 
    
    //每类水管在四个方向上(上左下右)的连通情况
    //1表示连通,0表示不连通 
    int dir[11][4] = {
    {1,0,0,1},//A 
    {1,1,0,0},//B
    {0,0,1,1},//C
    {0,1,1,0},//D
    {1,0,1,0},//E
    {0,1,0,1},//F
    {1,1,0,1},//G
    {1,0,1,1},//H
    {0,1,1,1},//I
    {1,1,1,0},//J
    {1,1,1,1}};//K
    
    //寻找节点 x 的所属集 
    int find(int x){
        if(x == pre[x]){
            return x;
        }
        int root = find(pre[x]);
        pre[x] = root;
        return root;
    }
    
    //flag = 1,尝试连接同一行紧邻的水管
    //flag = 2,尝试连接同一列紧邻的水管 
    void union_set(int row, int col, int flag){
        //草地坐标 
        int r1,r2;
        if(flag == 1){
            r1 = row * n + col;
            r2 = row * n + col + 1;
            
            //获取水管类型 
            int x = maps[row][col];
            int y = maps[row][col+1];
            //两种水管在左右方向上不能连通 
            if(dir[x][1] == 0 || dir[y][3] == 0){
                return; 
            }
        }
        else{
            r1 = row * n + col;
            r2 = (row + 1) * n + col;
            
            int x = maps[row][col];
            int y = maps[row+1][col];
            //两种水管在上下方向上不能连通 
            if(dir[x][2] == 0 || dir[y][0] == 0){
                return;
            }
        }
            
        r1 = find(r1);
        r2 = find(r2);
        
        if(height[r1] == height[r2]){
            pre[r1] = r2;
            height[r2]++;
        }
        else if(height[r1] > height[r2]){
            pre[r2] = r1;
        }
        else{
            pre[r1] = r2;
        }
    }
    
    int main(){
        while(scanf("%d %d", &m, &n) && (m >= 0 || n >= 0)){
            init();
            string str;
            for(int i=0;i<m;i++){
                cin>>str;
                for(int j=0;j<n;j++){
                    maps[i][j] = str[j] - 'A';
                }
            }
            //左右连通 
            for(int i=0;i<m;i++){
                for(int j=0;j<n-1;j++){
                    union_set(i, j, 1);
                }
            }
            //上下连通 
            for(int j=0;j<n;j++){
                for(int i=0;i<m-1;i++){
                    union_set(i, j, 2);
                }
            }
            //集合个数 
            int num = 0;
            for(int i=0;i<m*n;i++){
                if(i == pre[i]){
                    num++;
                }
            } 
            printf("%d
    ", num);
        }
    }
    作者:老干妈就泡面
    本文版权归作者和博客园共有,欢迎转载,但请给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    PTA 两个有序链表序列的合并
    PTA 递增的整数序列链表的插入
    PTA 链表逆置
    PTA 带头结点的链式表操作集
    _KPCR, _NT_TIB, _KPRCB
    FSOP
    逆向PspCreateProcess
    寒假训练 [GKCTF2020]Domo(4/250) 劫持vtable
    IO_FILE利用与劫持vtables控制程序流程、FSOP
    线程结构
  • 原文地址:https://www.cnblogs.com/bjxqmy/p/14483998.html
Copyright © 2020-2023  润新知