题目描述
这个魔法森林是怎样来的呢?魔法森林最初只是普通的森林,在它周围很远的地方都没有其他森林。但是有一天„„这是春天里的一个阳光灿烂的日子,森林里的所有居民都很高兴。但突然一声熊猫的吼叫宣告了伟大的森林议会就要开始了。所有动物放下它们的工作,立即赶往议会。其中刺猬 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; }