题目
题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=107574#problem/B
题目来源:2016.2.26群赛
简要题意:给定矩阵有黑白两色,每次可以将同色的连通块变成反色,求最少多少次矩阵单色。
题解
题意简洁,但是需要一定的图论功底,我是没想到,看了题解恍然大悟。
可以对同色的连通块缩点然后将相邻的连通块连边。
连通块向其他连通块的最长最短路的最小值就是答案了。
各种奇怪的问题都能转化为图论,图论博大精深啊。
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
// head
const int N = 45;
const int NN = N * N;
const int INF = 0x3f3f3f3f;
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
struct Edge {
int to, nxt;
Edge(int to, int nxt) : to(to), nxt(nxt) {}
Edge() {}
};
int head[NN];
Edge e[NN*4];
void addEdge(int from, int to, int cnt) {
e[cnt] = Edge(to, head[from]);
head[from] = cnt;
}
void init(int n) {
for (int i = 0; i <= n; i++) head[i] = -1;
}
char s[N][N];
int tag[N][N];
bool g[NN][NN];
int t, n, m;
bool isValid(int x, int y) {
return x > 0 && x <= n && y > 0 && y <= m;
}
void dfs(int x, int y, int v) {
tag[x][y] = v;
for (int dir = 0; dir < 4; dir++) {
int cx = x + dx[dir];
int cy = y + dy[dir];
if (tag[cx][cy] || !isValid(x, y)) continue;
if (s[x][y] != s[cx][cy]) continue;
dfs(cx, cy, v);
}
}
void buildEdge(int x, int y, int nx, int ny, int &ec) {
int p = tag[x][y], np = tag[nx][ny];
if (p == np || g[p][np]) return;
g[p][np] = g[np][p] = true;
addEdge(p, np, ec++);
addEdge(np, p, ec++);
}
void build() {
int color = 0, ec = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (tag[i][j]) continue;
color++;
dfs(i, j, color);
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (i < n) buildEdge(i, j, i+1, j, ec);
if (j < m) buildEdge(i, j, i, j+1, ec);
}
}
}
bool vis[NN];
int dis[NN];
int bfs(int be) {
if (vis[be]) return INF;
vis[be] = true;
memset(dis, -1, sizeof dis);
dis[be] = 0;
int ans = 0;
queue<int> q;
q.push(be);
while (!q.empty()) {
int cur = q.front();
q.pop();
ans = max(ans, dis[cur]);
for (int i = head[cur]; ~i; i = e[i].nxt) {
int nxt = e[i].to;
if (dis[nxt] != -1) continue;
dis[nxt] = dis[cur] + 1;
q.push(nxt);
}
}
return ans;
}
int main() {
scanf("%d", &t);
while (t--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%s", s[i]+1);
}
memset(tag, 0, sizeof tag);
memset(g, 0, sizeof g);
memset(vis, 0, sizeof vis);
init(n * m * 4);
build();
int ans = INF;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
ans = min(ans, bfs(tag[i][j]));
}
}
printf("%d\n", ans);
}
return 0;
}