HDU 1198 Farm Irrigation
这个题就是考建图,其实想起来以前玩的一个手机游戏就是这种类似铺管道的。
在矩阵里,每个点往4个方向看一下能不能和相邻点接上,但是这样的话要判断重复。更好的想法是往右下两个方向就行了,遍历矩阵按照外层从上到下,内层从左到右。
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const int MAXN = 50 + 2;
int M, N;
char mtx[MAXN][MAXN];
int x[4] = { -1,0,1,0 }; // 上左下右
int y[4] = { 0,-1,0,1 };
bool u[11] = { 0 };
bool l[11] = { 0 }; // left和right不能用
bool d[11] = { 0 };
bool r[11] = { 0 };
//bool vis[MAXN][MAXN][4];
int pre[MAXN*MAXN];
int conn;
struct edge
{
int n1, n2;
};
vector<edge> v;
void create_map()
{
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
char t0 = mtx[i][j];
for (int k = 2; k < 4; k++) // 从0,0 开始,其实只用向右下两个方向跑就行,不用担心边重复加了,也就不用vis了
{
int ni = i + x[k];
int nj = j + y[k];
if (ni < M && ni >= 0 && nj < N && nj >= 0 /*&& !vis[i][j][k]*/)
{
char t = mtx[ni][nj];
if (/*k == 0 && u[t0 - 'A'] && d[t - 'A'] || k == 1 && l[t0 - 'A'] && r[t - 'a'] ||*/ k == 2 && d[t0 - 'A'] && u[t - 'A'] || k == 3 && r[t0 - 'A'] && l[t - 'A'])
v.push_back({ i*N + j,ni*N + nj });
//vis[ni][nj][k ^ 2] = 1; // 异或2 就是 取反 低位第2位
}
}
}
}
}
void init()
{
u[0] = 1;l[0] = 1;
u[1] = 1;r[1] = 1;
l[2] = 1;d[2] = 1;
r[3] = 1;d[3] = 1;
u[4] = 1;d[4] = 1;
l[5] = 1;r[5] = 1;
u[6] = 1;l[6] = 1;r[6] = 1;
u[7] = 1;d[7] = 1;l[7] = 1;
l[8] = 1;r[8] = 1;d[8] = 1;
u[9] = 1;d[9] = 1;r[9] = 1;
u[10] = 1;l[10] = 1;d[10] = 1;r[10] = 1;
}
int f(int n)
{
int f0 = n, f1 = n;
for (; pre[f0] >= 0;)
{
f0 = pre[f0];
}
for (; pre[f1] >= 0;)
{
int t = f1;
f1 = pre[f1];
pre[t] = f0;
}
return f0;
}
void un(int n1, int n2)
{
int f1 = f(n1);
int f2 = f(n2);
if (f1 != f2)
{
conn++;
if (pre[f1] <= pre[f2])
{
pre[f1] += pre[f2];
pre[f2] = f1;
}
else
{
pre[f2] += pre[f1];
pre[f1] = f2;
}
}
}
int main()
{
init();
for (; ~scanf("%d%d", &M, &N);)
{
if (M == -1 || N == -1) break;
memset(pre, -1, sizeof pre);
//memset(vis, 0, sizeof vis);
conn = 0;
v.clear();
for (int i = 0; i < M; i++)
{
getchar(); //
for (int j = 0; j < N; j++)
scanf("%c", &mtx[i][j]);
}
create_map();
for (int i = 0; i < v.size(); i++)
{
if (conn == M*N - 1) break;
un(v[i].n1, v[i].n2);
}
// 删调试信息
printf("%d\n", M*N - conn);
}
return 0;
}