问题入口
https://leetcode.com/problems/regions-cut-by-slashes/
实现
这道题是对并查集的练习。并查集两个重要操作是Union和find。而合并什么是个问题。合并线段,将连在一起的线段合并为一个集合,这样就能得到线段数,但是线段数和区域数之间不是线性关系。例如下图(黑线用来划分网格,红线是题目给过的参数),线段数分别是4和5,但是区域数都是4。而合并区域的话,如果还把网格看成一个整体就没办法合并。
解决方案是把一个网格分成四个三角形,不论红线是“\”还是“/”,都无需顾虑。0号三角形始终可以和左边的区域合并,2号三角形始终可以和右边的区域合并,1号三角形始终和上边的区域合并,而3号三角形始终可以和下边的区域合并。很妙(但是我就想不出来……)。注意网格的位置也影响到了哪些区域可以合并,哪些区域不可以合并。
//找到父亲节点,并压缩路径
int find(int *parent, int p)
{
while(p!=parent[p])
{
parent[p] = parent[parent[p]];
p=parent[p];
}
return p;
}
void unionElement(int *parent, int *rank, int p, int q){
int pRoot = find(parent,p);
int qRoot = find(parent,q);
if(rank[pRoot]>rank[qRoot])
parent[qRoot]=pRoot;
else if(rank[pRoot]<rank[qRoot])
parent[pRoot]=qRoot;
else
{
parent[pRoot]=qRoot;
rank[qRoot]+=1;
}
}
int regionsBySlashes(char ** grid, int gridSize){
int *parent = malloc(sizeof(int)*gridSize*gridSize*4);
int *rank = malloc(sizeof(int)*gridSize*gridSize*4);
//初始化
for(int i=0;i<gridSize*gridSize*4;i++)
{
parent[i]=i;
rank[i]=1;
}
//合并每个网格的区域,O(gridSize²)
for(int i=0;i<gridSize;i++)
{
for(int j=0;j<gridSize;j++)
{
int u=gridSize*i*4+j*4;
if(grid[i][j]=='/')
{
unionElement(parent,rank,u,u+1);
unionElement(parent,rank,u+2,u+3);
}
else if(grid[i][j]=='\\')
{
unionElement(parent,rank,u,u+3);
unionElement(parent,rank,u+1,u+2);
}
else{
unionElement(parent,rank,u,u+3);
unionElement(parent,rank,u,u+1);
unionElement(parent,rank,u,u+2);
}
}
}
//合并整个网格的区域,O(gridSize²)
for(int i=0;i<gridSize;i++)
{
for(int j=0;j<gridSize;j++)
{
int u=gridSize*i*4+j*4;
if(i==0)
unionElement(parent,rank,u+3,u+4*gridSize+1);
else if(i==gridSize-1)
unionElement(parent,rank,u+1,u-4*gridSize+3);
else
{
if(j==0 || j==gridSize-1)
{
unionElement(parent,rank,u+1,u-4*gridSize+3);
unionElement(parent,rank,u+3,u+4*gridSize+1);
}
else{
unionElement(parent,rank,u,u-2);
unionElement(parent,rank,u+2,u+4);
}
}
if(j==0)
unionElement(parent,rank,u+2,u+4);
else if(j==gridSize-1)
unionElement(parent,rank,u,u-2);
else
{
if(i==0 || i==gridSize-1){
unionElement(parent,rank,u,u-2);
unionElement(parent,rank,u+2,u+4);
}
else{
unionElement(parent,rank,u+1,u-4*gridSize+3);
unionElement(parent,rank,u+3,u+4*gridSize+1);
}
}
}
}
//计数区域有多少个
int *tmp = malloc(sizeof(int)*gridSize*gridSize*4);
memset(tmp,0,sizeof(int)*gridSize*gridSize*4);
for(int i=0;i<gridSize*gridSize*4;i++){
tmp[find(parent,parent[i])]=1;
}
int count = 0;
for(int i=0;i<gridSize*gridSize*4;i++)
{
if(tmp[i]==1)
count++;
}
return count;
}