洛谷P2749 [USACO5.1]夜空繁星Starry Night

零、洛谷链接

一、简要题意

给你一张图,要找出所有八连通的连通块,规定不管旋转翻转后,只要相同的两个连通块算为同一种连通块。

对相同连通块染相同一个小写字母,按字典序输出染色后的图。

下面八个全为同一种连通块。

二、解法 + code

我们可以看出,本题最大的难点在于如何判断相似。

根据小学玄学知识&样例,我们有一些发现:

两个相似的图,从同一个点到别的点的直线距离(曼哈顿距离)相等。

来张图:

但是,我们在走连通块时,由于旋转和翻转的关系,并不能保障任意选择两点就是同一个点。

一看数据范围:\(n≤100\)

因此,可以将所有的点到其他点的曼哈顿距离都算出来,再加在一块求和,以这个数值作为比较相似的因素即可。

似乎是解决了?

快乐地把代码写出来♪:

// 仅放核心代码:
int main()
{
	scanf("%d%d", &m, &n);
	rep(i, 1, n)
	{
		rep(j, 1, m)
		{
			cin >> mapp[i][j];
		}
	}
	rep(i, 1, n)
	{
		rep(j, 1, m)
		{
			if(mapp[i][j] == '1')
			{
				tempcnt = 0;
				long long tempsum = 0;
				bfs(i, j); 
				rep(k, 1, tempcnt)
				{
					rep(l, 1, tempcnt)
					{
						tempsum += sqrt(abs(temp[k].x - temp[l].x) * abs(temp[k].x - temp[l].x) + abs(temp[k].y - temp[l].y) * abs(temp[k].y - temp[l].y));
					}
			//	cout << tempsum  << endl;
				}
			//	cout << "tempcnt:" << tempcnt << endl;
				int f = 0; 
				rep(k, 1, cnt)
				{
			
					if(tempsum == hhash[k])
					{
						f = 1;
						color(i, j, k); 
						break;
					} 
				}
				if(!f)
				{
					hhash[++cnt] = tempsum; 
				//	cout << cnt << endl;
					color(i, j, cnt);
				}
			}
		}
	}
	rep(i, 1, n)
	{
		rep(j, 1, m)
		{
			printf("%c", mapp[i][j]);
		}
		printf("\n");
	}
	return 0;
}

结果:

干得漂亮,有60分了

我们再来思考:因为曼哈顿距离带了根号,而这个代码里面全部取整了,所以两个仅有一点差别的图就会挂掉。、

所以带个double试试?

// by pjx Feb.
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <stack>
#define REP(i, x, y) for(register int i = x; i < y; i++)
#define rep(i, x, y) for(register int i = x; i <= y; i++)
#define PER(i, x, y) for(register int i = x; i > y; i--)
#define per(i, x, y) for(register int i = x; i >= y; i--)
using namespace std;
const int N = 605; 
int n, m, tempcnt;
char mapp[N][N];
double hhash[N], tempsum;
int cnt;
int dx[] = {0, -1, -1, -1, 0, 0, 1, 1, 1};//八个方向 
int dy[] = {0, -1, 0, 1, -1, 1, -1, 0, 1};
queue <int> qx, qy;
struct node{//用来存连通块每个点的坐标 
	int x, y;
}temp[N * N];
void bfs(int x, int y)//搜索连通块 
{
	temp[++tempcnt].x = x;
	temp[tempcnt].y = y;
	qx.push(x);
	qy.push(y);
	mapp[x][y] = '2';//如果搜到了一个点,那把它标记为未染色过但搜索过 
	while(!qx.empty())
	{
		int tx = qx.front();
		int ty = qy.front();
		qx.pop();
		qy.pop();
		rep(i, 1, 8)
		{
			int xx = tx + dx[i];
			int yy = ty + dy[i];
			if(xx >= 1 && xx <= n && yy >= 1 && yy <= m && mapp[xx][yy] == '1')
			{
				mapp[xx][yy] = '2';
				qx.push(xx);
				qy.push(yy);
				temp[++tempcnt].x = xx;
				temp[tempcnt].y = yy;				 
			}
		}
	}
}
void color(int x, int y, int word)//给这个图重新染色 
{
	qx.push(x);
	qy.push(y);
	mapp[x][y] = char(word + 'a' - 1);
	while(!qx.empty())
	{
		int tx = qx.front();
		int ty = qy.front();
		qx.pop();
		qy.pop();
		rep(i, 1, 8)
		{
			int xx = tx + dx[i];
			int yy = ty + dy[i];
			if(xx >= 1 && xx <= n && yy >= 1 && yy <= m && mapp[xx][yy] == '2')
			{
				mapp[xx][yy] = char(word + 'a' - 1);
				qx.push(xx);
				qy.push(yy);				 
			}
		}
	}
}
bool check()//判断两个连通块是否为同一种 
{
    tempsum = 0.0000;
    for(int k = 1; k <= tempcnt; k++)
	{
	    for(int l = 1; l <= tempcnt; l++)
		{
			tempsum += sqrt(double(abs(temp[k].x - temp[l].x)) * double(abs(temp[k].x - temp[l].x)) + double(abs(temp[k].y - temp[l].y)) * double(abs(temp[k].y - temp[l].y)));
			//因为带根号,为了更加精确,保留4位小数 
		}
	}
	for(int k = 1; k <= cnt; k++)
	{
		if(abs(tempsum - hhash[k]) <= 0.0001)//如果以前找到过与其总和一样的,就表明是第k种连通块 
		{
		    return 1;
		} 
	}
	return 0; 

}
int main()
{
	scanf("%d%d", &m, &n);
	rep(i, 1, n)
	{
		rep(j, 1, m)
		{
			cin >> mapp[i][j];
		}
	}
	rep(i, 1, n)
	{
		rep(j, 1, m)
		{
			if(mapp[i][j] == '1')
			{
				tempcnt = 0;
				bfs(i, j); 
                if(check())
                {
                   	for(int k = 1; k <= cnt; k++)
					{
						if(abs(tempsum - hhash[k]) <= 0.0001)//如果以前找到过与其总和一样的,就表明是第k种连通块 
						{
						    color(i, j, k);//染第k种颜色 
						    break;
						} 
					} 
                }
            	else//否则,增加新的一种,染新的一种颜色 
            	{
            	    hhash[++cnt] = double(tempsum); 
	              	color(i, j, cnt);
	           }
			}
		}
	}
	rep(i, 1, n)
	{
		rep(j, 1, m)
		{
			printf("%c", mapp[i][j]);
		}
		printf("\n");
	}
	return 0;
}

nice过了

posted @ 2021-03-05 22:57  panjx  阅读(81)  评论(0编辑  收藏  举报