NKOJ 2110 美丽的星空

NKOJ 2110 美丽的星空

思路

  • 洪水填充(BFS) + 多边形全等的判定。

实现方法

  • 这道题比较复杂,分为三个步骤。
    1. 用 BFS 求出有哪些星座并编号。
    2. 两两判全等。
      • 多边形的全等判定定理:如果两多边形每两个点之间的距离和相等,则它们全等。
      • 如果两个多边形全等,就将新的打上旧的的标记。否则就打一种新的标记。

代码

#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;
}

注意事项

  1. 注意在判全等时要外层从前往后判,内层从后往前判,这样才能时后面的按前面的标。
  2. 这道题有坑,要注意 \(n\)\(m\) 在本题中输入是反的。
  3. 注意在判断距离和相等时,只需要判断绝对差异与 \(eps\) 的大小,由于误差,一般不可能完全相等。
  4. 本题在调试的时候注意分块,在写代码时注意模块化,每一个功能一个函数,方便调试每一个功能。
posted @ 2024-12-14 09:49  hsr_ray  阅读(14)  评论(0)    收藏  举报