给你一个n*m的矩阵,上面只有两种字符,X或者O,每次可以同时改变相同颜色的一个连通块,上下左右连通才算连通,用最小的步数把这个图弄成全是X或者全是O,题意要是没看懂看下面的样例。
Sample Input
2
2 2
OX
OX
3 3
XOX
OXO
XOX
Sample Output
1
2
Hint
For the second sample, one optimal solution is:
Step 1. flip (2, 2)
XOX
OOO
XOX
Step 2. flip (1, 2)
XXX
XXX
XXX
思路:
这个可以用最短路来做(也可以直接广搜,因为是在格子上找距离),首先我们要把每一个连通块缩成一个点,然后把相邻的联通快之间建边,然后枚举每一个点为起点,跑单源最短路,然后对于每一个点的当前答案就是所有点中离他最远的那个,最后在在每一个最远的点钟找到最小的那个,为什么这么做是对的,我们就假设我们枚举的最短路的起点是中心点,我们从中心点往外扩,每一次绝对可以扩展一层,这
一层有两种扩展方式,改变中间或者改变要扩展的这层,画一下就理解了。。
#include<stdio.h> #include<string.h> #include<queue> #include<map> #define N_node 1600 + 100 #define N_edge 2000000 #define INF 100000000 using namespace std; typedef struct { int to ,next ,cost; }STAR; STAR E[N_edge]; int list[N_node] ,tot; int s_x[N_node]; int mapp[50][50] ,n ,m; int mk[50][50]; int dir[4][2] = {0 ,1 ,0 ,-1 ,1 ,0 ,-1 ,0}; map<int ,map<int ,int> >kk; void add(int a ,int b ,int c) { E[++tot].to = b; E[tot].cost = c; E[tot].next = list[a]; list[a] = tot; } int spfa(int s ,int n) { for(int i = 0 ;i <= n ;i ++) s_x[i] = INF; int mark[N_node] = {0}; mark[s] = 1; s_x[s] = 0; queue<int>q; q.push(s); while(!q.empty()) { int xin ,tou; tou = q.front(); q.pop(); mark[tou] = 0; for(int k = list[tou] ;k ;k = E[k].next) { xin = E[k].to; if(s_x[xin] > s_x[tou] + E[k].cost) { s_x[xin] = s_x[tou] + E[k].cost; if(!mark[xin]) { mark[xin] = 1; q.push(xin); } } } } int now = 0; for(int i = 1 ;i <= n ;i ++) if(now < s_x[i]) now = s_x[i]; return now; } bool ok(int x ,int y ,int ys) { return x >= 1 && x <= n && y >= 1 && y <= m && !mk[x][y] && mapp[x][y] == ys; } void DFS(int x ,int y ,int now ,int ys) { for(int i = 0 ;i < 4 ;i ++) { int xx = x + dir[i][0]; int yy = y + dir[i][1]; if(ok(xx ,yy ,ys)) { mk[xx][yy] = now; DFS(xx ,yy ,now ,ys); } } return ; } int main () { int i ,j ,t; char str[50]; scanf("%d" ,&t); while(t --) { scanf("%d %d" ,&n ,&m); for(i = 1 ;i <= n ;i ++) { scanf("%s" ,str); for(j = 1 ;j <= m ;j ++) mapp[i][j] = str[j-1] == 'X'; } memset(mk ,0 ,sizeof(mk)); int now = 0; for(i = 1 ;i <= n ;i ++) for(j = 1 ;j <= m ;j ++) { if(mk[i][j]) continue; mk[i][j] = ++now; DFS(i ,j ,now ,mapp[i][j]); } kk.clear(); memset(list ,0 ,sizeof(list)) ,tot = 1; for(i = 1 ;i <= n ;i ++) for(j = 1 ;j <= m ;j ++) { if(i > 1) { if(mk[i][j] != mk[i-1][j] && !kk[mk[i][j]][mk[i-1][j]]) { kk[mk[i][j]][mk[i-1][j]] = 1; add(mk[i][j] ,mk[i-1][j] ,1); } } if(i < n) { if(mk[i][j] != mk[i+1][j] && !kk[mk[i][j]][mk[i+1][j]]) { kk[mk[i][j]][mk[i+1][j]] = 1; add(mk[i][j] ,mk[i+1][j] ,1); } } if(j > 1) { if(mk[i][j] != mk[i][j-1] && !kk[mk[i][j]][mk[i][j-1]]) { kk[mk[i][j]][mk[i][j-1]] = 1; add(mk[i][j] ,mk[i][j-1] ,1); } } if(j < m) { if(mk[i][j] != mk[i][j+1] && !kk[mk[i][j]][mk[i][j+1]]) { kk[mk[i][j]][mk[i][j+1]] = 1; add(mk[i][j] ,mk[i][j+1] ,1); } } } int ans = INF; for(i = 1 ;i <= now ;i ++) { int tmp = spfa(i ,now); if(ans > tmp) ans = tmp; } printf("%d " ,ans); } return 0; }