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