https://www.luogu.org/problemnew/show/P2749
这道题目的意思就是有一个图,上有很多连通块,如果两个连通块能够通过旋转重合,那就认为这两个星系相同,相同的星系标记相同的星系符号,不同的不同。输出星系被标记后的情况
算法: DFS求连通块,奇怪方法 判重这道题目难就难在判重。但我们还是把整个过程讲一下
1.读入,将字符串转化成数组
2.枚举每个没有被标记星系标记的星系,DFS求出连通块的所有成员(DFS实现)
3.判断该星系是否出现过,(判断方法下面再讲),出现过的有原来的星系符号
4.输出现在讲一下判重的方法
枚举星系中每一个点与另外点的距离,判重该值是否出现过。
为什么这种方法可行?
1.如果同一个星系旋转成另一个星系,那这个值是不会变的;
2.加入两个星系这个值相同,而星系又不同,可证这种方法是矛盾的。Code:
#include <bits/stdc++.h>
#define N 510
using namespace std ;
char ch ;//星系颜色
int posx[N][N],posy[N][N] ;//pos(X,Y)[i][j]表示i星系的第j个点的位置是(posx[i][j],posy[i][j])
int tot ;//当前星系由多少个星星组成
int cnt=0,n,m ;//共有多少个星系
char ans[N][N] ;//答案
char c[N] ;//c[i]第i个星系的标号是c[i]
double s[N] ;
char a[N][N] ;
int dx[8]={1,1,1,0,0,-1,-1,-1} ;
int dy[8]={-1,0,1,-1,1,-1,0,1} ;
void dfs(int x,int y)
{
int tx,ty ;
for (int p=0;p<8;p++)
{
tx=x+dx[p] ;
ty=y+dy[p] ;
if (tx<=0 || ty<=0 || tx>n || ty>m || a[tx][ty]==0 || ans[tx][ty]!='0') continue ;
ans[tx][ty]=ch ;//标记星系颜色
tot++ ;
posx[cnt][tot]=tx ;
posy[cnt][tot]=ty ;
dfs(tx,ty) ;
}
return ;
}
double dist(int x2,int y2,int x3,int y3)
{
return sqrt((x2-x3)*(x2-x3)+(y2-y3)*(y2-y3));
}
int check(int w)//奇怪的判重方法。求所有点之间的距离
{
for (int i1=1;i1<=tot;i1++)
for (int j1=1;j1<=tot;j1++)
s[w]+=dist(posx[cnt][i1],posy[cnt][i1],posx[cnt][j1],posy[cnt][j1]);
for (int k1=1;k1<cnt;k1++)//是否存在相同的图形
if (fabs(s[w]-s[k1])<=0.00001) return k1;
return 0;
}
int main()
{
scanf("%d%d",&m,&n) ;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
ch=getchar();
if (ch!='0'&&ch!='1') ch=getchar() ;
if (ch=='0') a[i][j]=0 ;
else a[i][j]=1 ;
}
ch='a'-1 ;
memset(ans,'0',sizeof(ans));
cnt=0 ;tot=0 ;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (ans[i][j]=='0' && a[i][j]==1)
{
tot=1,cnt++ ;
posx[cnt][tot]=i;posy[cnt][tot]=j ;//第1个点
ch++ ;
c[cnt]=ch ;
ans[i][j]=ch,dfs(i,j) ;
int flag=0 ;//有没有重复
flag=check(cnt) ;
if (flag!=0){
ch-- ;
for (int k1=1;k1<=tot;k1++) ans[posx[cnt][k1]][posy[cnt][k1]]=c[flag];//一个一个点的改标记
}
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
printf("%c",ans[i][j]) ;
printf("\n") ;
}
return 0 ;
}