杭电1198 并查集

来源:互联网 发布:怎么做网络水军 编辑:程序博客网 时间:2024/04/28 12:09

本题不同于其他的并查集,看似很难,其实只要读懂题目,思路清晰,就很容易写出来,题目所示的田看似要用二维数组,但是我用一维数组也可以解决,先输入字符串,根据字符串匹配到是11种田中的哪一种,然后根据田的不同用一个二维数组表示不同的田,然后利用并查集,有水管相接的集合在一起;

代码如下:


  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
#include<stdio.h>
#include<string.h>
#include<math.h>
int father[3000],Rank[3000],i,b[3000];
int bo[11][4]= {{1,1,0,0},{1,0,1,0},{0,1,0,1},{0,0,1,1},{1,0,0,1},{0,1,1,0},{1,1,1,0},{1,1,0,1},{0,1,1,1},{1,0,1,1},{1,1,1,1}};
//11种田,以上、左、右、下的顺序和1、0表示其上、左、右、下有没有水管;
int find_set(int x)
{
if(x!=father[x])
father[x]=find_set(father[x]);
return father[x];
}
void Union(int x,int y)
{
x=find_set(x);
y=find_set(y);
if(x==y)
return;
if(Rank[x]>Rank[y])
father[y]=x;
else
{
if(Rank[y]==Rank[x])
Rank[y]++;
father[x]=y;
}
}
int main()
{
int n,m,i,j,x,y,z;
char a[60][60];
while(1)
{
int sum=0,flag=0;
for(i=0;i<3000;i++)
{
b[i]=i;
father[i]=i;
Rank[i]=0;
}
scanf("%d%d",&m,&n);
if(m==-1&&n==-1) break;
getchar();
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
scanf("%c",&a[i][j]); //利用二维数组输入
}
getchar();
}
for(i=0; i<m; i++)
{
for(j=0; j<n; j++)
{
if(i==0&&j>0)
{
x=a[i][j]-'A'; //匹配到田,例如如果a[i][j]=D,x=3;
y=a[i][j-1]-'A';
if(bo[x][1]+bo[y][2]==2) //根据匹配到的田看如果有水管相接则合并集合
{
flag=flag+1;
Union(b[j],b[j-1]); //这里的数组b[]表示所有的田,注意是一维数组,而不是二维数组
}
}
if(i>0&&j==0)
{
x=a[i][j]-'A';
y=a[i-1][j]-'A';
if(bo[x][0]+bo[y][3]==2)
{
Union(b[i*n],b[(i-1)*n]);flag=flag+1;
}
}
if(i>0&&j>0)
{
x=a[i][j]-'A';
y=a[i][j-1]-'A';
z=a[i-1][j]-'A';
if(bo[x][1]+bo[y][2]==2)
{
Union(b[i*n+j],b[i*n+j-1]);flag=flag+1;
}
if(bo[x][0]+bo[z][3]==2)
{
Union(b[i*n+j],b[i*n+j-n]);flag=flag+1;
}
}
}
}
for(i=0;i<n*m;i++)
{
if(father[i]==i)
sum=sum+1;
}
printf("%d\n",sum);
}
return 0;
}

0 0
原创粉丝点击