[USACO18OPEN]Multiplayer Moo
P4380 [USACO18OPEN]Multiplayer Moo
题目描述
奶牛们提出了一款创新性的新游戏,惊讶的是她们给这款游戏取了个最没创意的名字:“Moo”。 Moo游戏在一个由 N×N 个正方形格子组成的棋盘上进行,一头奶牛可以通过大叫一声“哞!”然后把她的数字编号写在这个格子里来占有这个格子。
在游戏结束的时候,每个格子中都包含一个数。在这个时刻,如果一头奶牛创建了一个由连通的格子组成的领域,大小不小于其他所有领域,那这头奶牛就获胜。一个“领域”被定义为一些具有相同数字编号的格子,其中每个在领域中的格子都直接与另一个同一领域中的格子通过上、下、左或者是右相邻(对角线不计)。
由于以单牛形式进行游戏有点无聊,奶牛们也对双牛组队进行游戏感兴趣。同一队的两头奶牛像之前一样可以创建一个领域,但是现在领域中的格子可以属于队伍中的任一头奶牛。
给定游戏棋盘的最终状态,请帮助奶牛们计算任何单头奶牛拥有的最大的领域包含的格子数量,以及任何两头奶牛组成的队伍占有的最大的领域包含的格子的数量。两头奶牛占有的领域必须要同时包含队伍中两头奶牛的编号,不能仅仅包含一头。
输入输出格式
输入格式:
输入的第一行包含 N ( 1≤N≤250 )。下面 NN 行,每行包含 NN 个整数(每个都在 0--1e6 之间),描述棋盘的最终状态。棋盘中至少出现两种不同的数字。
输出格式:
输出的第一行描述任何单头奶牛占有的最大领域大小,第二行描述任何两头奶牛的队伍占有的最大领域的大小。
输入输出样例
说明
在这个例子中,单头奶牛占有的最大领域是由五个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; }