传送门:HDU1198
题意:浇灌田地,图中的蓝色的线代表水管,水管能连起来的用一个泉源即可浇灌,问浇灌这片田地用需要多少个泉源
题解:并查集,将两个能用管子连起来的田地关联起来,变型成并查集模式
代码:
#include <iostream>
#include <cstdio>
using namespace std;
char shape[15][15]={"1010","1001","0110","0101",
"1100","0011","1011","1110",
"0111","1101","1111"};
//上下左右,给方块赋初值
int father[2505];
char Map[55][55];
int n,m;
int Find(int x)//并查集部分的查找函数
{
if(x==father[x])
return x;
return Find(father[x]);
}
void Union(int x,int y)//并查集部分的关联函数
{
int xx=Find(x);
int yy=Find(y);
father[xx]=yy;
}
void sovle()
{
int i,j,k,a,b;
for(i=0,k=1;i<n;i++)//每个方块循环判断能否和相邻方块链接
{
for(j=0;j<m;j++)
{
a=(int)Map[i][j]-65;
if(i!=0)//判断上方
{
b=(int)Map[i-1][j]-65;
if(shape[a][0]=='1'&&shape[b][1]=='1')//如果能链接,进行关联,下同
Union(k,k-m);
}
if(i!=n-1)//判断下方
{
b=(int)Map[i+1][j]-65;
if(shape[a][1]=='1'&&shape[b][0]=='1')
Union(k,k+m);
}
if(j!=0)//判断左方
{
b=(int)Map[i][j-1]-65;
if(shape[a][2]=='1'&&shape[b][3]=='1')
Union(k,k-1);
}
if(j!=m-1)//判断右方
{
b=(int)Map[i][j+1];
if(shape[a][3]=='1'&&shape[b][2]=='1')
Union(k,k+1);
}
k++;
}
}
}
int main()
{
int i,j,k,ans;
while(~scanf("%d%d",&n,&m)&&(n!=-1&&m!=-1))
{
for(i=0;i<n;i++)
scanf("%s",Map[i]);
for(i=0,k=1;i<n;i++)
for(j=0;j<m;j++)
{
father[k]=k;
k++;
}
sovle();
for(i=1,ans=0;i<=n*m;i++)
if(father[i]==i) ans++;
cout<<ans<<endl;
}
return 0;
}