NKOJ 2110 美丽的星空
思路
- 洪水填充(BFS) + 多边形全等的判定。
实现方法
- 这道题比较复杂,分为三个步骤。
- 用 BFS 求出有哪些星座并编号。
- 两两判全等。
- 多边形的全等判定定理:如果两多边形每两个点之间的距离和相等,则它们全等。
- 如果两个多边形全等,就将新的打上旧的的标记。否则就打一种新的标记。
代码
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;
struct node{int x,y;};
int n,m,cur;
char ANS='a';
int arr[505][505];
int vis[505][505];
int xx[505][165],yy[505][165];
char ans[505][505];
//int dx[]={1,0,-1,0,-1,1,-1,1};
//int dy[]={0,1,0,-1,-1,1,1,-1};
double dis(int x1,int y1,int x2,int y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
bool check(int tyx,int lzh){
double cnt1=0;
for(int i=1;i<=xx[tyx][0];i++){
for(int j=1;j<=xx[tyx][0];j++){
cnt1+=dis(xx[tyx][i],yy[tyx][i],xx[tyx][j],yy[tyx][j]);
}
}
double cnt2=0;
for(int i=1;i<=xx[lzh][0];i++){
for(int j=1;j<=xx[lzh][0];j++){
cnt2+=dis(xx[lzh][i],yy[lzh][i],xx[lzh][j],yy[lzh][j]);
}
}
if(abs(cnt1-cnt2)<0.000001) return 1;//注意点3
else return 0;
}
void mark(int tyx,int lzh){
for(int i=1;i<=xx[tyx][0];i++){
ans[xx[lzh][i]][yy[lzh][i]]=ans[xx[tyx][i]][yy[tyx][i]];
}
}
void book(int tyx){
for(int i=1;i<=xx[tyx][0];i++){
ans[xx[tyx][i]][yy[tyx][i]]=ANS;
}
ANS++;
}
void bfs(int x,int y){
queue<node> que;
que.push({x,y});
vis[x][y]=cur;
xx[cur][++xx[cur][0]]=x,yy[cur][++yy[cur][0]]=y;
while(!que.empty()){
node tp=que.front();
que.pop();
for(int i=-1;i<=1;i++){
for(int j=-1;j<=1;j++){
int tx=tp.x+i,ty=tp.y+j;
if(tx>=0&&tx<=n&&ty>=0&&ty<=m&&vis[tx][ty]==0&&arr[tx][ty]!=0){
xx[cur][++xx[cur][0]]=tx,yy[cur][++yy[cur][0]]=ty;
vis[tx][ty]=cur;
que.push({tx,ty});
}
}
}
}
}
int main(){
scanf("%d%d",&m,&n);//注意点2
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) scanf("%1d",&arr[i][j]);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) if(vis[i][j]==0&&arr[i][j]!=0) cur++,bfs(i,j);
}
// for(int i=1;i<=n;i++){
// for(int j=1;j<=m;j++){
// if(vis[i][j]==0) printf(" ");
// else printf("%.2d ",vis[i][j]);
// }
// puts("");
// }
for(int i=1;i<=cur;i++){
int flag=0;
for(int j=i-1;j>=1;j--){//注意点1
if(check(i,j)){
flag=1;
mark(j,i);
}
}
if(flag==0) book(i);
}
// book(1);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(vis[i][j]==0) printf("0");
else printf("%c",ans[i][j]);
}
puts("");
}
return 0;
}
注意事项
- 注意在判全等时要外层从前往后判,内层从后往前判,这样才能时后面的按前面的标。
- 这道题有坑,要注意 \(n\) 和 \(m\) 在本题中输入是反的。
- 注意在判断距离和相等时,只需要判断绝对差异与 \(eps\) 的大小,由于误差,一般不可能完全相等。
- 本题在调试的时候注意分块,在写代码时注意模块化,每一个功能一个函数,方便调试每一个功能。