洛谷Luogu-2749 [USACO5.1]夜空繁星Starry Night(DFS+判重) HQG_AC的博客

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





猜你喜欢

转载自blog.csdn.net/hqg_ac/article/details/79348103