用到的算法:并查集
题意:
给你一块地,这块地被分割成许多小正方形,每个正方形中都安装了水管,不同的正方形中可能安装的水管不同,一共有11种水管,分别用字母A~K表示,某些正方形地块的中心有水源,问你至少需要多少个水管,以保证整个正方形农田都能被灌溉。
实际上这题就是求不通的集合有多少个
思路:将每个正方形土地上的水管按照顺时针方向标记,有水管记为1,没有记为0;
如果一个矩形的上面和下面是相互连通的或者左边和右边相互连通,那么,这两个就是属于同一个集合;
可以先假定所有的集合都是相互独立的,如果是属于相同的集合,那么总集合数减去1,最后剩下的就是真正不同的集合数了
#include<cstdio>
char mp[60][60];
int p[3600],sum,n,m;
int r[11][4]={{1,0,0,1},{1,1,0,0},{0,0,1,1},{0,1,1,0},{1,0,1,0},{0,1,0,1},
{1,1,0,1},{1,0,1,1},{0,1,1,1},{1,1,1,0},{1,1,1,1}};//按顺时针来标记每个水管的连通情况
int findx(int x)
{
if(x!=p[x])
p[x]=p[findx(p[x])];//一直向上寻找最初的节点
return p[x];
}
int merge(int x,int y)//合并相同集合
{
x=findx(x),y=findx(y);
if(x==y)
return 0;
p[x]=y;
return 1;
//上面的0和1表示这两个集合在合并之前属不属于同一个集合,0表示属于,1表示不属于
}
int main()
{
while(scanf("%d %d",&n,&m),m>0||m>0)
{
sum=n*m;//假设每个集合都是各自独立的(都互不相通),即最多的集合数
int i,j;
for(i=0;i<sum;i++)
p[i]=i;
for(i=0;i<n;i++)
scanf("%s",mp[i]);
for(i=0;i<n;i++)
for(j=0;j<m;j++)
{
//如过一个矩形的上面和另一个矩形的下面相连,那么这两个属于同一个集合
if(i>0&&r[mp[i][j]-'A'][0]&&r[mp[i-1][j]-'A'][2])
sum-=merge(i*m+j,(i-1)*m+j);//如果原先是不同的集合,现在合并成一个相同的集合,那么总集合数就就少掉1,即一个集合被另一个集和吞并了
//同理左边和右边相连通,那么这两个也属于同一个集合
if(j>0&&r[mp[i][j]-'A'][3]&&r[mp[i][j-1]-'A'][1])
sum-=merge(i*m+j,i*m+j-1);
}
printf("%d\n",sum);
}
return 0;
}