• 魔法森林


    题目描述

    这个魔法森林是怎样来的呢?魔法森林最初只是普通的森林,在它周围很远的地方都没有其他森林。但是有一天„„这是春天里的一个阳光灿烂的日子,森林里的所有居民都很高兴。但突然一声熊猫的吼叫宣告了伟大的森林议会就要开始了。所有动物放下它们的工作,立即赶往议会。其中刺猬 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;
    }
  • 相关阅读:
    fwt
    fft,ntt
    loj6077
    高维前缀和
    hihocoder 1496 寻找最大值
    HDU 5977 Garden of Eden
    扩展crt
    有标号的DAG计数I~IV
    BZOJ 3160 万径人踪灭
    Codeforces Round #524 (Div. 2) F
  • 原文地址:https://www.cnblogs.com/rlddd/p/9853102.html
Copyright © 2020-2023  润新知