cup 6352: Multiplayer Moo(并查集+dfs处理连通块)

6352: Multiplayer Moo

时间限制: 2 Sec  内存限制: 256 MB
提交: 132  解决: 24
[提交] [状态] [讨论版] [命题人:admin]

题目描述

The cows have come up with a creative new game, surprisingly giving it the least creative name possible: "Moo".
The game of Moo is played on an N×N grid of square cells, where a cow claims a grid cell by yelling "moo!" and writing her numeric ID number in the cell.

At the end of the game, every cell contains a number. At this point, a cow wins the game if she has created a region of connected cells as least as large as any other region. A "region" is defined as a group of cells all with the same ID number, where every cell in the region is directly adjacent to some other cell in the same region either above, below, left, or to the right (diagonals don't count).

Since it is a bit boring to play as individuals, the cows are also interested in pairing up to play as teams. A team of two cows can create a region as before, but now the cells in the region can belong to either of the two cows on the team.

Given the final state of the game board, please help the cows compute the number of cells belonging to the largest region that any one cow owns, and the number of cells belonging to the largest region that can be claimed by a two-cow team. A region claimed by a two-cow team only counts if it contains the ID numbers of both cows on the team, not just one of the cows.

输入

The first line of input contains N (1≤N≤250). The next N lines each contain N integers (each in the range 0…106), describing the final state of the game board. At least two distinct ID numbers will be present in the board.

输出

The first line of output should describe the largest region size claimed by any single cow, and the second line of output should describe the largest region size claimed by any team of two cows.

样例输入

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

样例输出

5
10

提示

In this example, the largest region for a single cow consists of five 9s. If cows with IDs 1 and 9 team up, they can form a region of size 10.

【题意】:

给出一个n*n的方格图,每个方格上有一个数字(范围1~1e6),如果相邻两数字相同,则属于同一个连通块。

问(1):最大的连通块有几个方格?

问(2):如果可以任意的选两个数字,让他们可以互相联通,问这时的最大连通块大小是几个方格?

【分析】

问题(1)很好做,dfs爆搜即可,为了方便第二问,我这里第一问直接用了并查集。

并查集处理之后,每个点的 fa[i] 都指向本连通块内的同一个点。在第二问中,每个点有一个编号fa[i],有一个数值。

建图,相邻的连通块之间直接建图。

枚举所有连通块作为起点,内循环再枚举它的邻接点,就以这两个点的数值,从起点开始进行dfs,搜出能到达的所有等于这两个数值之一的点,并计数。对计数取最大值,最后即为答案。

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
const int MAX=1e6+7;

struct node{
    int t,next;
}edge[MAX];
int head[MAX],cnt;
void init()
{
    memset(head,-1,sizeof(head));
    cnt=0;
}
void add(int u,int v)
{
    edge[cnt]=node{v,head[u]};
    head[u]=cnt++;
}

int visver[MAX]; //时间戳标记点
bool visedge[MAX]; //标记边
int mmp[300*300];
int fa[MAX],n;
int father(int x){return x==fa[x]?x:fa[x]=father(fa[x]);}
int join(int x,int y){x=father(x);y=father(y);fa[x]=y;}
int getid(int x,int y){return (x-1)*n+y;}

int M[MAX]; //M[i]记录连通块i的大小
int dfs(int u,int tag,int num1,int num2)
{
    visver[u]=tag;
    int res=0;
    for(int i=head[u];~i;i=edge[i].next)
    {
        int v=edge[i].t;
        if(visedge[i]||visver[v]==tag||mmp[v]!=num1&&mmp[v]!=num2){continue;}
        visedge[i^1]=visedge[i]=true; //标记边
        res+=dfs(v,tag,num1,num2);
    }
    return res+M[u];
}

int main()
{
    scanf("%d",&n);
    for(int i=0;i<=n*n;i++)fa[i]=i;
    init();
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&mmp[getid(i,j)]);
            if(i>1&&mmp[getid(i,j)]==mmp[getid(i-1,j)])
                join(getid(i,j),getid(i-1,j));
            if(j>1&&mmp[getid(i,j)]==mmp[getid(i,j-1)])
                join(getid(i,j),getid(i,j-1));
        }
    }
    int ans1=0,ans2=0;
    for(int i=1;i<=n*n;i++) //统计连通块大小
        ans1=max(ans1,++M[father(i)]);
    int dir[2][2]={0,1,1,0}; //right,down
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            for(int k=0;k<2;k++)
            {
                int x=i+dir[k][0];
                int y=j+dir[k][1];
                if(x>n||y>n||mmp[getid(i,j)]==mmp[getid(x,y)])continue;
                int u=father(getid(x,y));
                int v=father(getid(i,j));
                add(u,v); add(v,u); //相邻但不相等
            }
        }
    }
    int tag=1; //时间戳
    for(int u=1;u<=n*n;u++)if(M[u]>0) //枚举存在的起点
    {
        for(int i=head[u];~i;i=edge[i].next) //枚举另一个
        {
            int v=edge[i].t;
            if(visedge[i])continue;
            int res=dfs(u,tag++,mmp[u],mmp[v]); //以u为起点,寻找两数字,标记边
            ans2=max(ans2,res);
        }
    }
    ans2=max(ans2,ans1);
    printf("%d\n%d\n",ans1,ans2);
}

猜你喜欢

转载自blog.csdn.net/winter2121/article/details/81205597
CUP