POJ 13H:最长的环

13H:最长的环

总时间限制: 

1000ms

内存限制: 

131072kB

描述

给定一个N*M的格子矩阵,行的编号从上到下为1到N,列的编号从左到右为1到M,每个格子里面放着0或1。

定义一个环是一个格子序列(这个序列中的格子互不相同),序列中连续的两个格子要求他们相邻(有一条共同的边,一个格子至多与上下左右的四个格子相邻),并且序列开头和结尾的格子也要相邻。并且环还需要同时满足以下三个条件:

1. 这个序列中的所有格子他们里面是放的数都是1。

2. 这个环中的任何一个格子都只与这个环中的两个格子相邻

3. 矩阵中所有的1要么在这个环上,要么在这个环外面。(环的外面定义为:环上的格子首尾相接构成一个封闭的图形,其他1的格子要在这个封闭图形的外部)

现在要求求出这个矩阵中的最长的环。(环的长度就是格子序列的长度)

输入

第一行是数据组数t(t < 20)
对于每组数据,第一行是N和M,接下来是一个N*M的01矩阵。(N <= 1000,M <= 1000)

输出

对每组数据,输出最长的环的长度。
每组数据输出占一行

样例输入

4
3 3
111
101
111
3 3
010
101
010
3 3
111
111
111
5 5
11111
10001
10101
10001
11111

样例输出

8
0
4
0

提示

样例解释
1. 只有一个长度为8的环
2. 没有环
3. 最长的环长度为4,这个环可以是(1,1)(1,2)(2,2)(2,1),需要注意的是(1,1)(1,2)(1,3)(2,3)(2,2)(2,1)这6个格点不算是一个环,因为不满足题目中的条件2:(1,2),(2,2)这两个格点与环中的三个格点相邻。
4. 只有一个环,但是由于环的里面有个1,所以构不成环。

萌新刚刚学c++,遇到这个题其实有一点点不太会做。

但是由于想到了可以染色,于是就做出来了^_^

先同时染黑白块再染黑环,白环确定闭合,黑环确定无向内多链接的环(如下)

11111

10001

10111

10001

11111(这是不符合要求的)

白色八项染色消除开环,黑环四向染色消除向内多链接的边缘,最后看看有没有黑没染,如果有,那么还有环内杂点。

代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
int map[1002][1002] = { 0 };
int color[1002][1002] = { 0 };
const int dm[8] = { 0,0,-1,1,1,1,-1,-1 };
const int dn[8] = { 1,-1,0,0,1,-1,1,-1 };
bool CorrectColor[1000000] = { 0 };
int length[100000] = { 0 };
int M, N;
void paint(int m, int n, int painter)
{
	color[m][n] = painter;
	for (int i = 0; i < 8; i++)
	{
		if (map[m + dm[i]][n + dn[i]] == -1)
		{
			CorrectColor[painter] = false;
		}
		else if ((map[m + dm[i]][n + dn[i]] == 0) & (color[m + dm[i]][n + dn[i]] == -1))
		{
			paint(m + dm[i], n + dn[i], painter);
		}
		else if ((map[m + dm[i]][n + dn[i]] == 1) & (color[m + dm[i]][n + dn[i]] != painter))
		{
			length[painter] ++;
			color[m + dm[i]][n + dn[i]] = painter;
		}
	}
}
bool paint1(int m, int n, int painter)
{
	color[m][n] = painter+114514;
	int temp = 0;
	for (int i = 0; i < 4; i++)
	{
		if (map[m + dm[i]][n + dn[i]] == 1 && ((color[m + dm[i]][n + dn[i]] == painter) | (color[m + dm[i]][n + dn[i]] == painter + 114514)))
			temp += 1;
	}
	if (temp != 2) return false;
	bool tmp = true;
	for (int i = 0; i < 4; i++)
	{
		if (map[m + dm[i]][n + dn[i]] == 1 && (color[m + dm[i]][n + dn[i]] == painter))
			tmp &= paint1(m + dm[i], n + dn[i], painter);
	}
	return tmp;
}
bool exam(int painter)
{
	bool flag0 = true, flag1 = true;
	for (int m=1;m<=M;m++)
		if (flag1)
			for (int n=1;n<=N;n++)
				if (map[m][n] == 1 & color[m][n] == painter)
				{
					if (flag0 == true)
					{
						flag0 = false;
						if (!paint1(m, n, painter)) flag1 = false;
					}
					else flag1 = false;
				}
	return flag1;
}
int main()
{
	int N23g9 = 0; cin >> N23g9;
	while (N23g9-- > 0)
	{
		cin >> M >> N;
		memset(map, -1, sizeof(map));
		memset(color, -1, sizeof(color));
		memset(CorrectColor, true, sizeof(CorrectColor));
		memset(length, 0, sizeof(length));
		char temp;
		for (int i = 1; i <= M; i++)
		{
			cin.get();
			for (int j = 1; j <= N; j++)
			{
				cin.get(temp);
				map[i][j] = temp - '0';
			}
		}
		for (int i = 0; i <= M+1; i++)
		{
			map[i][0] = -1; map[i][N+1] = -1;
		}
		for (int i = 0; i <= N+1; i++)
		{
			map[0][i] = -1; map[M+1][i] = -1;
		}
		int painter = 0;
		int lenmax = 0;
		for (int m = 1; m <= M; m++)
			for (int n = 1; n <= N; n++)
				if (map[m][n] == 0 & color[m][n] == -1)
				{
					paint(m, n, painter); 
					if ((length[painter] > lenmax) & CorrectColor[painter])
						if (exam(painter)) lenmax = length[painter];
					painter++;
				}
		if (lenmax > 0) cout << lenmax << endl;
		else
		{
			bool temp = false;
			for (int i = 1; i < M; i++)
				if (!temp)
					for (int j = 1; j < N; j++)
						if (map[i][j] + map[i + 1][j] + map[i + 1][j + 1] + map[i][j + 1] == 4)
							temp = true;
			if (temp == true) cout << 4 << endl;
			else cout << 0 << endl;
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值