题目链接~~>
做题感悟:比赛时最后一个多小时就不淡定了,看哪个哪个不会,处于不断切题状态,那时应该找一个做出来几率大的题思考。
题意:这题就两种颜色,颜色相同且有公共边的(或者通过另一个相同的颜色连接)为一个连通块,如果翻转其中一个,与它在同一个连通块里的都要改变颜色,求达到相同颜色的最小步数。
解题思路:dfs ( 建图) + bfs ( 寻找最优解 ) .
1) dfs( 建图 ) ,因为翻转的时候每翻转连通块中一个整个连通块都翻转,这样你可以将其看成一个有边相连的无向图,每个边的两个顶点颜色都不一样。
2) bfs( 寻找最优解 ) , 建完图后就需要翻转计算最优解,可以枚举从每一点开始翻转所得到的最小步数,那怎样寻找最小步数 ? 假如从 v 这个顶点出发,那么与 v 相邻的顶点颜色必定都与 v 相反,so~> 你只需要把 v的颜色翻转,v与它相邻的所有顶点都是同一个颜色,这时可以把这些顶点看成一个连通块(顶点),再向四周扩展,再次扩展时,周围的颜色必定与此连通块颜色相反,再将它变成与周围顶点相同的颜色,这样又合并成为一个连通块……这样一直进行下去取最大步数。最后从最大步数中取出最小的步数即为最优解。
代码:
#include<stdio.h> #include<iostream> #include<map> #include<stack> #include<string> #include<string.h> #include<stdlib.h> #include<math.h> #include<vector> #include<queue> #include<algorithm> using namespace std ; const double PI = 3.1415926 ; const double esp = 1e-4 ; const int md= 2810778 ; const int INF = 999999999 ; const int MX = 1625 ; int n,m ; char s[50][50] ; int dx[5]={1,-1,0,0},dy[5]={0,0,1,-1} ; int num[50][50] ; // 用于标记属于哪个集合 bool vis[MX] ; vector<int>G[MX] ; struct node { int x,step ; } ; int bfs(int x) { int time=0 ; queue<node>q ; node curt,next ; memset(vis,false,sizeof(vis)) ; curt.x=x ; curt.step=0 ; vis[x]=true ; q.push(curt) ; while(!q.empty()) { curt=q.front() ; q.pop() ; if(time<curt.step) time=curt.step ; int nx=G[curt.x].size() ; next.step=curt.step+1 ; for(int i=0 ;i<nx ;i++) { next.x=G[curt.x][i] ; if(!vis[next.x]) { vis[next.x]=true ; q.push(next) ; } } } return time ; } bool search(int x,int y) { if(x<0||y<0||x>=n||y>=m) return false ; return true ; } void dfs(int x,int y,int ct,char ch) { for(int i=0 ;i<4 ;i++) { int sx=x+dx[i] ; int sy=y+dy[i] ; if(search(sx,sy)) { if(s[sx][sy]==ch) { if(num[sx][sy]==-1) { num[sx][sy]=ct ; dfs(sx,sy,ct,ch) ; } } else if(num[sx][sy]!=-1) { int temp=num[sx][sy] ; G[ct].push_back(temp) ; // 建双向边 G[temp].push_back(ct) ; } } } } void init() // 初始化 { memset(num,-1,sizeof(num)) ; for(int i=0 ;i<n*m ;i++) G[i].clear() ; } int main() { int Tx,cnt ; scanf("%d",&Tx) ; while(Tx--) { scanf("%d%d",&n,&m) ; init() ; cnt=0 ; for(int i=0 ;i<n ;i++) scanf("%s",s[i]) ; for(int i=0 ;i<n ;i++) for(int j=0 ;j<m ;j++) if(num[i][j]==-1) // 如果没访问过 { num[i][j]=cnt++ ; dfs(i,j,cnt-1,s[i][j]) ; } int ans=INF ; for(int i=0 ;i<cnt ;i++) // 广搜寻找最优解 { int mx=bfs(i) ; ans=ans > mx ? mx : ans ; } printf("%d\n",ans) ; } return 0 ; }