Farm Irrigation HDU - 1198 (并查集)

版权声明:chen_zan_yu https://blog.csdn.net/chen_zan_yu_/article/details/89391121

滴答滴答---题目链接

思路: 

  • 水管连通本质上就是集合的合并,最后求有几个集合的问题,很容易想到并查集
  • 只需要对每个地块与右方和下方的地块进行合并即可,合并之前先判断是否能连通,
  • 若能连通则合并,不能连通,则不能合并
  • 每种水管用一个由'0'和'1'组成的长度为4的字符串代表,
  • 分别表示上下左右四边是否有接口,'0'无,'1'有
#include <iostream>
#include<stdio.h>
using namespace std;
const int maxn=550;
int fa[maxn];
char f[maxn][maxn];
int n,m;
int cnt;
const int type[11][4]={{1,1,0,0},{0,1,1,0},{1,0,0,1},{0,0,1,1},{0,1,0,1},{1,0,1,0},{1,1,1,0},{1,1,0,1},{1,0,1,1},{0,1,1,1},{1,1,1,1}};
int find_set(int x){
    int r=x;
    while(r!=fa[r]) r=fa[r];
    int i=x;
    int j;
    while(i!=r){
        j=fa[i];
        fa[i]=r;
        i=j;
    }
    return r;
}
void unit_set(int x1,int y1,int x2,int y2,int dir){

    if(x2>n||y2>m)return;//超出地图不合并
    bool flag=false;//标记是否可连通
    int t1,t2;
    t1=f[x1][y1]-'A';
    t2=f[x2][y2]-'A';
    if(dir==1){
        if(type[t1][3]&&type[t2][1])flag=true;//竖直方向 
    }
    else{
        if(type[t1][2]&&type[t2][0])flag=true;//水平方向
    }
    if(flag){//合并 
        int a=find_set((x1-1)*m+y1);
        int b=find_set((x2-1)*m+y2);
        if(a!=b){
            fa[b]=a;
            --cnt;//消去一个水井
        }
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m)){
        if(n==-1&&m==-1)break;
        for(int i=1;i<=n*m;i++){
            fa[i]=i;
        }
        cnt=n*m;//初始化,假设所有田里都有水井
        for(int i=1;i<=n;i++){
            scanf("%s",f[i]+1);
        }
        for(int i=1;i<=n;i++){//统一向右or下合并
            for(int j=1;j<=m;j++){
                unit_set(i,j,i+1,j,1);//竖直 
                unit_set(i,j,i,j+1,0);//水平
            }
        }
        printf("%d\n",cnt);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/chen_zan_yu_/article/details/89391121