首先我们用1和0来表示一块田的四个方向是否有管道 有的话就是1 没有就是0 比如:A 表示的就是1100 B表示的就是0110 以此这样表示
在同一行我们只需判断当前这块田第三个字符和下一块田的第一个字符是否相等 并且都等于一
在同一列我们只需判断当前这块田第二个字符和下一块田的第四个字符是否相等并且都等于一
列如:
2 2
DK
HF
转换后为
0011 1111
1101 1010
D的第三个字符等于一,K的第一个字符等于一 所以 DK可以连通
同理得其他的田是否连通
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
string a[12];
char map[100][100];
int vis[100][100];
int pre[100];
int suan(char x,char y)
{
int num;
int i = x - 'A' + 1;
int j = y - 'A' + 1;
if(a[i][2]=='1'&&a[j][0]=='1')
num = 1;
else
num = 0;
return num;
}
int suan1(char x,char y)
{
int num;
int i = x - 'A' + 1;
int j = y - 'A' + 1;
if(a[i][3]=='1'&&a[j][1]=='1')
num = 1;
else
num = 0;
return num;
}
int find(int x)
{
int r = x;
while(pre[r]!=r)
{
r = pre[r];
}
return r;
}
int main()
{
a[1] = "1100",a[2] = "0110",a[3] = "1001",a[4] = "0011",a[5] = "0101",a[6] = "1010";
a[7] = "1110",a[8] = "1101",a[9] = "1011",a[10] = "0111",a[11] = "1111";
int n,m;
while(~scanf("%d%d",&n,&m))
{
if(n==-1&&m==-1)
break;
memset(vis,0,sizeof(vis));
int sum = n*m;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
scanf(" %c",&map[i][j]);
}
}
for(int i = 1; i <= n * m; i++)
pre[i] = i;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
//printf(" %c",map[i][j]);
if(j+1<=m)
{
int ans = suan(map[i][j],map[i][j+1]);
int fx = find((i-1)*m+j);
int fy = find((i-1)*m+j+1);
if(fx!=fy&&ans == 1) ///注意: 如果下一块田已经访问过 不减一
{
pre[fx] = fy;
sum--;
}
}
if(i+1<=n)
{
int ans1 = suan1(map[i][j],map[i+1][j]);
int fx = find((i-1)*m+j);
int fy = find((i+1-1)*m+j);
if(fx!=fy&&ans1==1)
{
pre[fx] = fy;
sum--;
}
}
}
}
printf("%d\n",sum);
}
return 0;
}