Fire Game FZU - 2150 搜索 分类讨论

题解

两个熊孩子可以选择2个地点进行点火,分三种情况讨论,1个联通块,2个联通块,2个以上联通块。
2个以上联通块肯定就没办法烧完了直接-1。
2个联通块时由于数据量很小,对于每个联通块,枚举点火点BFS得到当前联通块所有点都着火的所需时间,每个联通块不同点火点的时间取最小,两个联通块的时间取最大。
1个联通块时,由于数据很小,先将当前联通块以每个位置为点火点,引燃每个位置的所需时间求出来。
枚举两个点火点作为当前方案,对于每个位置当前点燃时间则为两个点火点引燃当前位置的较小值,然后每个位置取最大则为当前方案所需时间,每个方案取最小即为答案。

AC代码

#include <stdio.h>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
#define fst first
#define sed second
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const int N = 20;
int dir[4][2] = { -1, 0, 1, 0, 0, -1, 0, 1 };
char g[N][N];
bool vis[N][N];
int f[N][N][N][N]; //f[i][j][x][y]以ij为起点到达xy的时间
int n, m, blk;
vector<pair<int, int> > vec[110];

struct node
{
	int x, y, k;
	node(int a, int b, int c) : x(a), y(b), k(c) {}
};
void DFS(int x, int y)
{
	vec[blk].push_back(make_pair(x, y)); //每个联通块的点存入vec
	vis[x][y] = 1;
	for (int i = 0; i < 4; ++i)
	{
		int xx = x + dir[i][0], yy = y + dir[i][1];
		if (xx >= 1 && xx <= n && yy >= 1 && yy <= m && g[xx][yy] == '#' && !vis[xx][yy])
			DFS(xx, yy);
	}
}
void BFS(int p[N][N], int xx, int yy)
{
	memset(vis, 0, sizeof(vis));
	queue<node> q;
	q.push(node(xx, yy, 0));
	vis[xx][yy] = 1;
	p[xx][yy] = 0;
	while (!q.empty())
	{
		int x = q.front().x, y = q.front().y, k = q.front().k + 1; q.pop();
		for (int i = 0; i < 4; ++i)
		{
			xx = x + dir[i][0], yy = y + dir[i][1];
			if (xx >= 1 && xx <= n && yy >= 1 && yy <= m && g[xx][yy] == '#' && !vis[xx][yy])
				q.push(node(xx, yy, k)), vis[xx][yy] = 1, p[xx][yy] = k;
		}
	}
}
int main()
{
#ifdef LOCAL
	freopen("C:/input.txt", "r", stdin);
#endif
	int T;
	cin >> T;
	for (int ti = 1; ti <= T; ti++)
	{
		printf("Case %d: ", ti);
		for (int i = 0; i < 110; ++i)
			vec[i].clear();
		memset(f, 0x3f, sizeof(f));
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; ++i)
			scanf("%s", g[i] + 1);
		blk = 0; //联通块
		memset(vis, 0, sizeof(vis));
		for (int i = 1; i <= n; ++i)
			for (int j = 1; j <= m; ++j)
				if (g[i][j] == '#' && !vis[i][j])
					DFS(i, j), ++blk;
		//cout << blk << endl;
		int ans = 0;
		if (blk > 2)
			ans = -1;
		else if (blk == 2)
		{
			for (int b = 0; b < 2; ++b) //两个联通块
			{
				int mi = INF;
				for (int i = 0; i < vec[b].size(); ++i)
				{
					int x = vec[b][i].fst, y = vec[b][i].sed;
					BFS(f[x][y], x, y); //得到以xy为起点到达其它点最短路
					int mx = 0;
					for (int j = 0; j < vec[b].size(); ++j)
					{
						int xx = vec[b][j].fst, yy = vec[b][j].sed; //其它所有点
						mx = max(mx, f[x][y][xx][yy]); //所有点取max
					}
					mi = min(mi, mx); //所有选择点取min
				}
				ans = max(ans, mi); //两个分块取max
			}
		}
		else //单联通块
		{
			for (int i = 0; i < vec[0].size(); ++i)
			{
				int x = vec[0][i].fst, y = vec[0][i].sed;
				BFS(f[x][y], x, y); //求每个点为起点到达其他点最短路
			}
			ans = INF;
			for (int a = 0; a < vec[0].size(); ++a)
			{
				int ax = vec[0][a].fst, ay = vec[0][a].sed;
				for (int b = a; b < vec[0].size(); ++b)
				{
					int bx = vec[0][b].fst, by = vec[0][b].sed; //选两个点
					int mx = 0;
					for (int i = 0; i < vec[0].size(); ++i)
					{
						int xx = vec[0][i].fst, yy = vec[0][i].sed; //其它所有点
						mx = max(mx, min(f[ax][ay][xx][yy], f[bx][by][xx][yy])); //ab取min 所有点取max
					}
					ans = min(ans, mx); //所有选择点取min
				}
			}
		}
		printf("%d\n", ans);
	}

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值