题目链接:https://ac.nowcoder.com/acm/contest/993/I/
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

奶牛们提出了一款创新性的新游戏,惊讶的是她们给这款游戏取了个最没创意的名字:“Moo”。

Moo游戏在一个由N×N个正方形格子组成的棋盘上进行,一头奶牛可以通过大叫一声“哞!”然后把她的数字编号写在这个格子里来占有这个格子。

在游戏结束的时候,每个格子中都包含一个数。在这个时刻,如果一头奶牛创建了一个由连通的格子组成的领域,大小不小于其他所有领域,那这头奶牛就获胜。一个“领域”被定义为一些具有相同数字编号的格子,其中每个在领域中的格子都直接与另一个同一领域中的格子通过上、下、左或者是右相邻(对角线不计)。

由于以单牛形式进行游戏有点无聊,奶牛们也对双牛组队进行游戏感兴趣。同一队的两头奶牛像之前一样可以创建一个领域,但是现在领域中的格子可以属于队伍中的任一头奶牛。

给定游戏棋盘的最终状态,请帮助奶牛们计算任何单头奶牛拥有的最大的领域包含的格子数量,以及任何两头奶牛组成的队伍占有的最大的领域包含的格子的数量。两头奶牛占有的领域必须要同时包含队伍中两头奶牛的编号,不能仅仅包含一头。

输入描述

输入的第一行包含N(1≤N≤250)。下面NN行,每行包含N个整数(每个都在0…1000,000之间),描述棋盘的最终状态。棋盘中至少出现两种不同的数字。

输出描述

输出的第一行描述任何单头奶牛占有的最大领域大小,第二行描述任何两头奶牛的队伍占有的最大领域的大小。

输入

4
2 3 9 3
4 9 9 1
9 9 1 7
2 1 1 9

输出

5
10

说明

在这个例子中,单头奶牛占有的最大领域是由五个9组成的。如果编号为1和9的奶牛组队,她们可以形成一个大小为10的领域。

解题思路

题意:求只出现一种数字的最大连通块的大小和只出现两种数字的最大连通块的大小。
思路:第一个数很好算,DFS一边就行,并给每一个联通块序列化,然后在for扫遍将建立关系;
因为可能会出现重复,所以用set去重一下,然后枚举一个点到另一点,DFS删除经过的边。
因为每一次DFS需要标记点,不能每一次都初始化,可以用一个栈存储,每一次搜索完后,对栈的中标记的数取消标记。

Accepted Code:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 255;
bool vis[MAXN][MAXN], vist[MAXN * MAXN];
int n, tot, cnt, cot, dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
int mp[MAXN][MAXN], res[MAXN][MAXN], num[MAXN * MAXN], ber[MAXN * MAXN], f[MAXN * MAXN << 2];
struct edge {
    int u, v;
    bool operator < (const edge & s) const {
        if (s.u != u)
            return s.u > u;
        return s.v > v;
    }
}p;
stack <int> S;
set <edge> spt;
struct edga {
    int u, v, w;
}e[MAXN * MAXN << 3];
void Union(int u, int v) {
    e[++cot] = (edga){f[u], v, 1};
    f[u] = cot;
}
void init() {
    tot = cnt = cot = 0;
    memset(vis, false, sizeof(vis));
    memset(vist, false, sizeof(vist));
}
bool Judge(int x, int y) {
    if (x >= 0 && x < n && y >= 0 && y < n)
        return true;
    return false;
}
void DFS1(int x, int y) {
    cnt++;
    res[x][y] = tot;
    vis[x][y] = true;
    for (int i = 0; i < 4; i++) {
        int tx = x + dir[i][0];
        int ty = y + dir[i][1];
        if (Judge(tx, ty) && !vis[tx][ty] && !(mp[x][y] - mp[tx][ty]))
            DFS1(tx, ty);
    }
}
void DFS2(int s, int v1, int v2) {
    S.push(s);
    cnt += num[s];
    vist[s] = true;
    for (int i = f[s]; i; i = e[i].u) {
        int t = e[i].v;
        if (!vist[t] && e[i].w && !((ber[t] - v1) && (ber[t] - v2))) {
            e[i].w = 0;
            DFS2(t, v1, v2);
        }
    }
}
void Cons() {
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            for (int k = 0; k < 4; k++) {
                int tx = i + dir[k][0];
                int ty = j + dir[k][1];
                if (Judge(tx, ty) && res[i][j] != res[tx][ty]) {
                    p = (edge){res[i][j], res[tx][ty]};
                    if (p.u > p.v)
                        swap(p.u, p.v);
                    spt.insert(p);
                }
            }
        }
    }
}
int slove(int s) {
    int ans = 0;
    for (int i = f[s]; i; i = e[i].u) {
        int t = e[i].v;
        if (!vist[t] && e[i].w) {
            cnt = 0;
            DFS2(s, ber[s], ber[t]);
            ans = max(ans, cnt);
            while (!S.empty()) {
                vist[S.top()] = false;
                S.pop();
            }
        }
    }
    return ans;
}
int main() {
    init();
    int max_1 = 0, max_2 = 0;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            scanf("%d", &mp[i][j]);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (!vis[i][j]) {
                cnt = 0;
                DFS1(i, j);
                max_1 = max(cnt, max_1);
                num[tot] = cnt;
                ber[tot++] = mp[i][j];
            }
        }
    }
    Cons();
    set <edge>::iterator it;
    for (it = spt.begin(); it != spt.end(); it++) {
        Union(it -> u, it -> v);
        Union(it -> v, it -> u);
    }
    for (int i = 0; i < tot; i++)
        max_2 = max(max_2, slove(i));
    printf("%d\n%d\n", max_1, max_2);
    return 0;
}