[USACO18OPEN]Multiplayer Moo

题目描述

奶牛们提出了一款创新性的新游戏,惊讶的是她们给这款游戏取了个最没创意的名字:“Moo”。 Moo游戏在一个由 N×N 个正方形格子组成的棋盘上进行,一头奶牛可以通过大叫一声“哞!”然后把她的数字编号写在这个格子里来占有这个格子。

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

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

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:
4
2 3 9 3
4 9 9 1
9 9 1 7
2 1 1 9
输出样例#1:
5
10

说明

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

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

c++ code:

#include <bits/stdc++.h>
#define IT set<Node>::iterator
using namespace std;

const int N =300 + 10;
int mmap[N][N],flag[N][N],num[N*N],dig[N*N];
bool vis[N][N],vised[N*N];
int cnt;
int dir[4][2]={1,0,0,1,0,-1,-1,0},tot,n,cot,head[N*N*4];
stack<int>sta;
struct Edge{
    int to,next,flag;
}edge[N*N*4];
void add(int u,int v)
{
    edge[cot].next=head[u];
    edge[cot].to=v;
    edge[cot].flag = 1;
    head[u]=cot++;
}

struct Node{
    int u,v;
    bool operator<(const Node &b) const
    {
        return u == b.u?v < b.v:u < b.u;
    }
};

set<Node>s;
int dfs(int x,int y)
{
    int ans = 0;
    vis[x][y] = true;
    flag[x][y] = tot;
    for(int i = 0;i < 4;i++)
    {
        int dx = x + dir[i][0],dy = y + dir[i][1];
        if(dx >= 1 && dx <= n && dy >= 1 && dy <= n && !vis[dx][dy] && mmap[x][y] == mmap[dx][dy])
            ans += dfs(dx,dy) + 1;
    }
    return ans;
}

void LK()
{
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= n;j++)
        {
            for(int k = 0;k < 4;k++)
            {
                int dx = i + dir[k][0],dy = j + dir[k][1];
                Node now;
                if(dx >= 1 && dx <= n && dy >= 1 && dy <= n && flag[i][j] != flag[dx][dy])
                {
                    now.u = flag[dx][dy];now.v = flag[i][j];
                    if(now.u > now.v)
                        swap(now.u,now.v);
                    s.insert(now);
                }
            }
        }
}

int dfs(int now,int val1,int val2)
{
    int ans = num[now];
    vised[now] = true;
    sta.push(now);
    for(int i=head[now];i != -1;i = edge[i].next)
    {
        int to = edge[i].to;
        if(!vised[to] && (dig[to] == val1 || dig[to] == val2) && edge[i].flag)
        {
            edge[i].flag = 0;
            ans += dfs(to,val1,val2);
        }
    }
    return ans;
}

int solve(int now)
{
    int ans = 0;
    for(int i=head[now];i != -1;i = edge[i].next)
    {
        int to = edge[i].to;
        if(!vised[to] && edge[i].flag)
        {
            int val = dfs(now,dig[to],dig[now]);
            ans = max(val,ans);
            while(!sta.empty())
                vised[sta.top()] = false,sta.pop();
        }
    }
    vised[now] = true;
    return ans;
}

int main()
{
    tot = 0;cot = 0;
    memset(vis,false,sizeof(vis));
    memset(flag,0,sizeof(flag));
    for(int i = 0; i < N*N*4;i++)
        head[i] = -1;
    scanf("%d",&n);
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= n;j++)
            scanf("%d",&mmap[i][j]);
    int ans = 0,ant = 0;
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= n;j++)
            if(!vis[i][j])
            {
                ++tot;
                int val = dfs(i,j)+1;
                ans = max(ans,val);
                num[tot] = val;
                dig[tot] = mmap[i][j];
            }
    LK();
    Node node;
    for(IT it = s.begin();it != s.end();it++)
    {
        node = *it;
        add(node.u,node.v);
        add(node.v,node.u);
    }
    memset(vised,false,sizeof(vised));
    for(int i = 1;i <= tot;i++)
        ant = max(ant,solve(i));
    printf("%d\n%d\n",ans,ant);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lemon-jade/p/9375480.html