http://www.icpc.moe/onlinejudge/showProblem.do?problemCode=3781
题意:
在n*m矩阵的图定义连通区域为x值或y值相同且颜色相同的连通,连通具有传递性
每次可以把一个连通区域颜色反转(O变X,X变O)
问把所有块的颜色变为X最小的步数
思路:
乍一看,翻开随便一个点会影响一大片联通块翻转,实际上只是吓人的,我们其实可以把每个联通块看成一个点。
把原图处理一下,所有在一个联通块的点直接看成一个点,相邻的不同联通块显然颜色不同(否则可以可并为一个块嘛!) 那么我们直接暴力枚举,以任一个联通块作为起点,显然的话,每翻一个联通块,就会把周围所有的联通块并入,形成一个大的联通块 。。直接模拟 就好
初始化联通块并编号,例如从联通块i开始,每一次,把当前联通块周围的所有联通块编号标记为1,然后丢进队列,每次再从队列取出联通块编号,把其周围联通块合并。。。。bfs乱搞就ac了
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <set> #include <vector> #include <iostream> using namespace std; const double pi=acos(-1.0); double eps=0.000001; int min(int a,int b) {return a<b?a:b;} int max(int a,int b) {return a>b?a:b;} int dx[]={0,0,1,-1}; int dy[]={1,-1,0,0}; char mp[45][45]; int id=1; int vis[45][45]; int flag; int check[45][45]; int n,m; struct node { int x,y,step; node(int a=0,int b=0,int c=0){x=a,y=b;step=c;} }; vector<node > node_in_col[40*40+5]; vector <int> sb[40*40+5]; void dfs(int x,int y ) { int i,j; if (vis[x][y]) return ; flag=1; vis[x][y]=id; node_in_col[id].push_back(node(x,y)); for (i=0;i<4;i++) { int xx=x+dx[i]; int yy=y+dy[i]; if (!(xx>=1&&xx<=n&&yy>=1&&yy<=m))continue; if (mp[xx][yy]!=mp[x][y]) continue; dfs(xx,yy); } } int col[40*40+5]; struct bf { int t,c; bf(int a,int b){c=a;t=b;} }; int solve(int cc) { memset(col,0,sizeof(col)); int ret=0; queue<bf>q; int i,j; bf st(cc,0); q.push(st); col[cc]=1; while(!q.empty()) { bf tp=q.front();q.pop(); ret=max(ret,tp.t); int tmp=tp.c; for (int i=0;i<sb[tmp].size();i++) { int tt=sb[tmp][i]; if (col[tt]) continue; q.push(bf(tt,tp.t+1) ); col[tt]=1; } } return ret; } int main() { int t;cin>>t; while(t--) { memset(vis,0,sizeof vis); cin>>n>>m; int i,j; for (i=1;i<=n;i++) scanf("%s",mp[i]+1); for (i=1;i<=n*m;i++) sb[i].clear(),node_in_col[i].clear(); id=1; for (i=1;i<=n;i++) { for (j=1;j<=m;j++) { flag=0; dfs(i,j ); if (flag) id++; } } /*for (i=1;i<=n;i++) { for (j=1;j<=m;j++) { printf("%2d",vis[i][j]); } printf("\n"); }*/ for (i=1;i<id;i++) { for (j=0;j<node_in_col[i].size();j++) { int x=node_in_col[i][j].x; int y=node_in_col[i][j].y; for (int k=0;k<4;k++) { int xx=x+dx[k]; int yy=y+dy[k]; if( !(xx>=1&&xx<=n&&yy>=1&&yy<=m))continue; sb[i].push_back(vis[xx][yy]); } } } /* printf("%d\n",node_in_col[4].size()); for (j=0;j<sb[4].size();j++) printf("%d ",sb[4][j]); */ int minn=40*40+1; for (i=1;i<id;i++) minn=min(minn,solve(i)); printf("%d\n",minn); } return 0; }