题目链接:点击打开链接
题目大意:
在一个由1 0组成的图中,对于和任何一个1,和它相邻的所有的1为一个星系,赋一个小写字母。最后输出新图。
解题思路:
刚开始bfs裸搜一遍,发现不对,tm的对于形状相同的星系就算没在一起也要赋和之前相同的小写字母。惊了,遂想到hash,然而,这就触碰到我的知识盲区了。。。真的不知道hash那个值怎么得来比较好。就去看了大佬的讲解,就是每个点与它平均值得差的四次方相加。不过hash的方法肯定很多,这只是其中一种。然后就是每次先将得到的图遍历一遍。得到它的hash值,然后去找之前有没有存过相同的,找到的话就返回跟它相同的小写字母,否则就将字母+1,。细节看代码,
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <set>
#include <functional>
#define rank ra
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
#define hash haha
using namespace std;
typedef long long ll;
int dx[8]={-1,-1,0,1,1,1,0,-1};
int dy[8]={0,-1,-1,-1,0,1,1,1};
const int mod=1000007;
int n,m,num,idx;
char c;
char a[110][110];
bool vis[110][110];
int head[mod];
struct node
{
int area,next;
char flag;
ll hash;
}edge[mod<<2];
struct point
{
int x,y;
}p[200];
void add(int x,int y)
{
num++;
p[num].x=x;
p[num].y=y;
}
void dfs(int x,int y) //找所有连接起来的点
{
for(int i=0;i<8;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&a[xx][yy]=='1'&&vis[xx][yy]==0)
{
add(xx,yy);
vis[xx][yy]=1;
dfs(xx,yy);
}
}
}
double vc(int x,int y,double dx,double dy)
{
return 1.0*(x-dx)*(x-dx)*(x-dx)*(x-dx)+1.0*(y-dy)*(y-dy)*(y-dy)*(y-dy);
}
char hash(int area,ll ha)
{
int key=ha%mod;
for(int i=head[key];i!=-1;i=edge[i].next) //通过链表查找hash 有损hash
{
if(edge[i].area==area&&edge[i].haha==ha)
return edge[i].flag;
}
edge[idx].area=area;
edge[idx].haha=ha;
edge[idx].flag=c++;
edge[idx].next=head[key];
head[key]=idx++;
return c-1;
}
void vs(int x,int y)
{
num=0;
add(x,y);
vis[x][y]=1;
dfs(x,y);
double dx=0,dy=0;
int nx=0,ny=0;
for(int i=1;i<=num;i++)
{
nx+=p[i].x;
ny+=p[i].y;
}
dx=nx*1.0/num; //求出平均值
dy=ny*1.0/num;
double ha=0;
for(int i=1;i<=num;i++)
ha+=vc(p[i].x,p[i].y,dx,dy); //查找hash值
char k=hash(num,(ll)(ha*100)); //得到hash值乘10的倍数
for(int i=1;i<=num;i++)
a[p[i].x][p[i].y]=k; //赋值
}
void read()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf(" %c",&a[i][j]);
}
int main()
{
while(scanf("%d%d",&m,&n)!=EOF)
{
c='a';
idx=0;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
read(); //输入
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(a[i][j]=='1') //找到1就搜索
vs(i,j);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
printf("%c",a[i][j]);
}
printf("\n");
}
}
return 0;
}