1402.星空之夜(哈希映射)
题目链接:https://www.acwing.com/problem/content/description/1404/
这题非常有意思,让我学到了连通块的哈希映射方式,看题目时发现这题最大的难点是如何辨识“星群”,八个不同的方向需要如何映射成一个确定的字母值,想了许久没有任何可行思路。忍不住看了下题解才知道是映射各个连通点之间的距离之和。
题解思路如下:
1:首先存取下深搜过程的连通块坐标点。
2:计算连通块各点之间的距离和,计算欧几里得距离(我一开始用的没有开根的欧几里得距离的整数值映射,过不了最后的数据点,说明冲突较大,利用double小数的特性,能减少哈希冲突概率/曼哈顿距离也不行)进行哈希映射。
题外话,从这个映射方式让我开始思考,是否现在的图片识别就是用类似这种原理的算法,将图片像素点抽象成矩阵。再借此哈希映射来查看相似度。
代码如下
#include<bits/stdc++.h>
#define endl '\n';
using namespace std;
const int mod=1e9+7;
typedef long long ll;
const int N=1e4;
int n,m;
char maps[500][500];
int stepx[9]={0,-1,-1,0,1,1,1,0,-1};
int stepy[9]={0,0,-1,-1,-1,0,1,1,1};
vector<double>hashs;
void dfs(int x,int y,vector<pair<int,int>>&q)
{
q.push_back({x,y});
maps[x][y]='0';
for(int i=1;i<=8;i++)
{
int dx=stepx[i]+x;
int dy=stepy[i]+y;
if(dx<=0||dy<=0||dx>n||dy>m||maps[dx][dy]=='0')continue;
dfs(dx,dy,q);
}
}
double get_distance(vector<pair<int,int>>&q)//计算连通距离和
{
double sum=0;
for(int i=0;i<q.size();i++)
{
int x=q[i].first;
int y=q[i].second;
for(int j=i+1;j<q.size();j++)
{
int x2=q[j].first;
int y2=q[j].second;
sum+=sqrt((x-x2)*(x-x2)+(y-y2)*(y-y2));
}
}
return sum;
}
void turn(vector<pair<int,int>>&q,char c)//将连通块转变成字母
{
for(int i=0;i<q.size();i++)
{
int x=q[i].first;
int y=q[i].second;
maps[x][y]=c;
}
return;;
}
char check(double x)
{
for(int i=0;i<hashs.size();i++)
{
if(fabs(hashs[i]-x)<1e-6)return i+'a';//查找哈希表
}
char c=hashs.size()+'a';
hashs.push_back(x);
return c;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>m>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>maps[i][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(maps[i][j]=='1')
{
vector<pair<int,int>>q;
dfs(i,j,q);
double sum=get_distance(q);
char c=check(sum);
turn(q,c);
}
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)cout<<maps[i][j];
cout<<endl;
}
return 0;
}

浙公网安备 33010602011771号