滴答滴答---题目链接
思路:
- 水管连通本质上就是集合的合并,最后求有几个集合的问题,很容易想到并查集
- 只需要对每个地块与右方和下方的地块进行合并即可,合并之前先判断是否能连通,
- 若能连通则合并,不能连通,则不能合并
- 每种水管用一个由'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;
}