题目背景
高高的星空,簇簇闪耀的群星形态万千。一个星座(cluster)是一群连通的星组成的非空连通星系,这里的连通是指水平,垂直或者对角相邻的两个星星。一个星座不能是另一个更大星座的一部分, 星座可以相似(similar)。如果两个星座有相同的形状,而且包括相同数目的星体,那么不管其方向性如何,就算相似。一般而言,星座可能的方向有八个,如图1所示。
题目描述
夜空可以表示为一份天体图(sky map),它是一个由字符0和1组成的二维矩阵,字符1表示所在的位置有一颗星;字符0表示该位置上是空的.给定一份天体图,用同一个小写英文标识(mark)相似的所有星座。相似的星座必须用相同的字母标识,不同的星座表示为不同的字母。标识一个星座,就是将其中各星体对应的字符1替换为相应的小写字母.
输入输出格式
输入格式:
文件的前两行分别记录了天体图的宽度W、深度H。而天体图则是由接下来的H行表示,每行包括W个字符. ……
输出格式:
输出文件记录了天体图与文件STARRY.IN相似,不同之处在于,各个星座按照“任务”中的要求进行了标识(mark)。
对于同一个输入文件,可能会有很多不同的标识,此时,输出字典序最小的标识。
输入输出样例
输入样例#1:
23 15 10001000000000010000000 01111100011111000101101 01000000010001000111111 00000000010101000101111 00000111010001000000000 00001001011111000000000 10000001000000000000000 00101000000111110010000 00001000000100010011111 00000001110101010100010 00000100110100010000000 00010001110111110000000 00100001110000000100000 00001000100001000100101 00000001110001000111000
输出样例#1:
a000a0000000000b0000000 0aaaaa000ccccc000d0dd0d 0a0000000c000c000dddddd 000000000c0b0c000d0dddd 00000eee0c000c000000000 0000e00e0ccccc000000000 b000000e000000000000000 00b0f000000ccccc00a0000 0000f000000c000c00aaaaa 0000000ddd0c0b0c0a000a0 00000b00dd0c000c0000000 000g000ddd0ccccc0000000 00g0000ddd0000000e00000 0000b000d0000f000e00e0b 0000000ddd000f000eee000
解题思路
这道题就是标准的找联通块,但是它的星系可以旋转八个方向,这个判重就很麻烦,所以我们就用一个简单的数学道理来判重:两个图形,如果它们自身的任意两点的距离和相等,证明它们是同一图形。
题解
1 #include<bits/stdc++.h> 2 #define N 105 3 using namespace std; 4 int n,m,Star=0;//当前星系的种类 5 bool flag[N][N];//搜索时的标记 6 char mp[N][N];//存图 7 double star[N];//每个星系的距离之和 8 int dir[8][2]={0,1,0,-1,1,0,-1,0,1,1,1,-1,-1,1,-1,-1};//八个方向 9 struct node{//坐标 10 int x; 11 int y; 12 }; 13 node galaxy[N];//搜到的当前星系的每一个星星的坐标 14 void Galaxy(int x)//处理当前星系的字母 15 { 16 double ans=0;//距离总和 17 int flag=0; 18 for(int i=1;i<=x;i++) 19 { 20 for(int j=1;j<=x;j++) 21 { 22 ans+=sqrt((galaxy[i].x-galaxy[j].x)*(galaxy[i].x-galaxy[j].x)+(galaxy[i].y-galaxy[j].y)*(galaxy[i].y-galaxy[j].y)); 23 //平面内两点距离公式 24 } 25 } 26 for(int i=1;i<=Star;i++) 27 { 28 if(fabs(star[i]-ans)<=0.00001)//如果相差小于0.00001,我们判断为同一星系 29 { 30 flag=i;//记录星系,方便存字母 31 break; 32 } 33 } 34 if(!flag)//如果它是一个新的星系 35 { 36 Star++;//星系种类增加 37 star[Star]=ans; 38 for(int i=1;i<=x;i++) 39 { 40 mp[galaxy[i].x][galaxy[i].y]='a'+Star-1;//存储字母 41 } 42 return; 43 } 44 for(int i=1;i<=x;i++) 45 { 46 mp[galaxy[i].x][galaxy[i].y]='a'+flag-1;//找相似星星的字母 47 } 48 } 49 void bfs(int x,int y)//找联通块 50 { 51 int num=1;//开始就起点一颗星星 52 queue<node> q; 53 q.push((node){x,y}); 54 flag[x][y]=true;///标记 55 galaxy[num]=(node){x,y};//记录坐标 56 while(!q.empty()) 57 { 58 node head=q.front(); 59 q.pop(); 60 for(int i=0;i<8;i++) 61 { 62 int tx=head.x+dir[i][0]; 63 int ty=head.y+dir[i][1]; 64 if(tx>=1&&ty>=1&&tx<=n&&ty<=m&&!flag[tx][ty]&&mp[tx][ty]=='1')//越界与标记 65 { 66 flag[tx][ty]=true; 67 num++;//这个星系里的星星数量增加 68 galaxy[num]=(node){tx,ty};//存储坐标 69 q.push((node){tx,ty}); 70 } 71 } 72 } 73 Galaxy(num);//开始判断这个星系 74 } 75 int main() 76 { 77 cin>>m>>n; 78 for(int i=1;i<=n;i++) 79 { 80 for(int j=1;j<=m;j++) 81 { 82 cin>>mp[i][j];//存图 83 } 84 } 85 for(int i=1;i<=n;i++) 86 { 87 for(int j=1;j<=m;j++) 88 { 89 if(!flag[i][j]&&mp[i][j]=='1')//没被搜过的星星开始找星系 90 { 91 bfs(i,j); 92 } 93 } 94 } 95 for(int i=1;i<=n;i++) 96 { 97 for(int j=1;j<=m;j++) 98 { 99 cout<<mp[i][j];//输出 100 } 101 cout<<endl; 102 } 103 }