魔法森林

题目描述

这个魔法森林是怎样来的呢?魔法森林最初只是普通的森林,在它周围很远的地方都没有其他森林。但是有一天„„这是春天里的一个阳光灿烂的日子,森林里的所有居民都很高兴。但突然一声熊猫的吼叫宣告了伟大的森林议会就要开始了。所有动物放下它们的工作,立即赶往议会。其中刺猬 Harry 来得最慢,于是鸟们开始没有耐性地唱歌,苍蝇们开始飞来飞去(不断地),野鹿开始发出一些奇怪地声音,老狐狸正在狡猾地观察着她身边的所有东西,而那只大黑熊又开始感到饥饿了,于是它开始用草莓充饥。没有人知道将会发生什么,没有人——除了 Olivia——一只聪明的猫头鹰。


—我亲爱的朋友们,我相信每个人都同意这点——我们的森林不能让一个游客的眼睛感到非常愉快。森林里有太多种树了。更确切地说,有两种——松树和柏树。我们应该把其中一种树全部消灭掉。你们建议消灭哪种呢?-“谁在乎呢„„”大黑熊喃喃自语地说道,然后它又一口把另一个草莓吃了下去。大多数其他的动物都感到非常困惑,它们都没有听明白。-好了,接下来我要问第二个问题了:我们应该怎样干掉那些树呢? Olivia 说道。就在这个时候,一个巫师在一束亮光之下出现了。(在这之前他一直藏在一棵树后面。)他的名字Genzibabel。事实上,这些消灭树的计划都是他的主意——他想练习一下他刚学会的魔法。

 

于是他开始对动物们说:-我可以把你们的森林里的树全部变成其中一种。我可以施展一种叫做Floodfill-Altertree 的魔法。我需要做的只是选定其中一棵树,然后我会施展魔法。在魔法放出的一瞬间,我选中树所在的一片和它相同种类的树都会变成另外一种树(也就是说,松树变成柏树,柏树变成松树)。用这个方法,我可以用一次魔法就把一整片相同树的连接区域变成另外一种。但是施展这个魔法是非常辛苦的(要耗费 MP 啊!) , 所以我想尽可能少地使用这个魔法。

 

要记住,我们可以把森林想象成由树组成的矩形。两棵树相邻当且仅当他们所在的单位正方形有公共边。你要解决的问题正和这个巫师还有这些动物们一样。

你要求出最少要施展多少次魔法才可以把所有的树只变成一种。


输入

输入文件的第一行有一个数B,表示下面有B组数据。每组数据第一行有两个整数R,C(1<=R,C<=150),表示森林的行数和列数。再下面是一个R行C列的01矩阵,表示森林。1表示松树,0表示柏树。矩阵的任何位置没有空格。


输出

每组数据输出一行,每行一个整数:最少施展魔法的次数。


样例输入

2
1 10
1011001101
9 9
001111100
010000010
100101001
100101001
100000001
101000101
100111001
010000010
001111100


样例输出

3
2

 

数据随机生成。



题解

这题面是真的长。

考试的时候一脸懵逼,总感觉没那么简单。。

其实就是把每个连通块缩点,然后距离为 1 的连通块连边,再从每个连通块开始 bfs,取每次 bfs 最大值中的最小值。

#include<queue>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long

int fx[4]={0,1,0,-1};
int fy[4]={1,0,-1,0};

const int maxn=150+50;
const int inf=1e9;

int fir[maxn*maxn],to[8*maxn*maxn],nex[8*maxn*maxn],ecnt;
int T,n,m,id[maxn][maxn],tot,dis[maxn*maxn];
char c[maxn][maxn];
bool vis[maxn][maxn],p[maxn*maxn],LInk[5000][5000];

template<typename T>void read(T& aa){
    char cc; ll ff;aa=0;cc=getchar();ff=1;
    while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
    if(cc=='-') ff=-1,cc=getchar();
    while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
    aa*=ff;
}

void add(int u,int v){
    nex[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;
}

void dfs(int x,int y){
    vis[x][y]=true;id[x][y]=tot;
    for(int i=0;i<4;i++){
        int xx=x+fx[i];
        int yy=y+fy[i];
        if(vis[xx][yy]) continue;
        if(xx<=n&&xx>=1&&yy<=m&&yy>=1&&c[xx][yy]==c[x][y])
        dfs(xx,yy);
    }
}

int bfs(int x){
    queue<int> q;
    memset(dis,0,sizeof(dis));
    memset(p,false,sizeof(p));
    dis[x]=0;int ans=0;
    q.push(x);p[x]=true;
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int e=fir[u];e;e=nex[e]){
            int v=to[e];
            if(p[v]) continue;
            q.push(v);
            p[v]=true;
            dis[v]=dis[u]+1;
            ans=max(ans,dis[v]);
        }
    }
    return ans;
}

int main(){
//    freopen("forest.in","r",stdin);
//    freopen("forest.out","w",stdout);
    read(T);
    while(T--){
        memset(nex,0,sizeof(nex));
        memset(to,0,sizeof(to));
        memset(fir,0,sizeof(fir)); ecnt=0;tot=0;
        int ans=inf;
        memset(c,0,sizeof(c));
        memset(vis,false,sizeof(vis));
        memset(id,0,sizeof(id));
        memset(LInk,false,sizeof(LInk));
        read(n),read(m);
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) cin>>c[i][j];
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        if(!vis[i][j]){
            ++tot;dfs(i,j);
        }
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        for(int k=0;k<4;k++){
            int xx=i+fx[k];
            int yy=j+fy[k];
            if(xx>=1&&xx<=n&&yy>=1&&yy<=m){
                int v=id[xx][yy],u=id[i][j];
                if(v==u) continue;
                if(LInk[u][v]) continue;
                add(u,v);add(v,u);LInk[u][v]=LInk[v][u]=true;
            }
        }
        for(int i=1;i<=tot;i++) ans=min(ans,bfs(i));
        cout<<ans<<endl;
    }
//  noip 2018 rp ++
    return 0;
}

 

posted @ 2018-10-25 21:39  rld  阅读(290)  评论(0编辑  收藏  举报