P3057 题解

### 前言
题目传送门

\(\color{red}{see}\space \color{green}{in}\space \color{blue}{my}\space \color{purple}{blog}\)

在学校比赛时遇到了这一题,写一篇题解纪念一下。

本题是最短路好题。

思路

此题明显是最短路。

我们需要求任意两点的最短路的最大值,即全源最短路。

本题共有 \(n^2\) 个点,如果跑 Floyd 时间复杂度是 \(O(n^6)\),非常极限,不是本题正解。

但是,我又不会写 Johnson 全源最短路,怎么办呢?

每个点朝四周建边,容易发现,边的数量不超过 \(4 \times n^2\)

想到这里,明显可以跑 \(n^2\) 次 dijkstra 实现,因为当边数较小时,跑多次 dijkstra 会比 Floyd 快。

此处 dijkstra 是使用优先队列实现。

那么就很容易写出代码了。

思路总结

  1. 读入数据。

  2. 每个点朝四周建边。

  3. 写一个 dijkstra 的模版。

  4. 统计最大值,输出。

代码

最短路模版没有强制要求,按照自己的习惯写 dijkstra 当然可以。

还有一个小细节:边数 \(m\) 最多有多少?

\(m = 905 * 4 * 2 = 7200\)

#include <iostream>
#include <cstdio>
#include <queue>
#define N 905
#define M 7205
using namespace std;
int n, nn, A, B;
int dict[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
bool a[35][35];
struct Node
{
	int now, nxt, w;
}e[M];
int head[N], cur;
void add(int x, int y, int k)
{
	e[++cur].now = y;
	e[cur].nxt = head[x];
	e[cur].w = k;
	head[x] = cur;
}
struct Dis
{
	int pos, len;
	bool operator <(const Dis &t) const
	{
		return len > t.len; 
	}
}dis[N];
bool vis[N];
int dijkstra(int first) 
{
	priority_queue <Dis> Q;
	for (int i = 1; i <= nn; i++) dis[i].pos = i, dis[i].len = 2147483647, vis[i] = false;
	dis[first].len = 0;
	Q.push(dis[first]);
	while (!Q.empty())
	{
		int topi = Q.top().pos;
		Q.pop();
		if (vis[topi]) continue;
		vis[topi] = true;
		for (int i = head[topi]; i; i = e[i].nxt)
			if (dis[topi].len + e[i].w < dis[e[i].now].len)
			{
				dis[e[i].now].len = dis[topi].len + e[i].w;
				Q.push(dis[e[i].now]);
			}
	}
    //此处有是惟一与普通模版不同的地方,需要找出最大值。
	int maxn = 0;
	for (int i = 1; i <= nn; i++) maxn = max(maxn, dis[i].len);
	return maxn;
}
void Input()
{
	scanf("%d%d%d", &n, &A, &B);
	nn = n * n;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
		{
			char x;
			cin >> x;
			if (x == '(') a[i][j] = true;
		}
}
void get_edge()
{
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			for (int k = 0; k < 4; k++)
			{
				int x = i + dict[k][0], y = j + dict[k][1];
				if (!(1 <= x && x <= n && 1 <= y && y <= n)) continue;
				int t1 = n * (i-1) + j, t2 = n * (x-1) + y;
				if (a[i][j] == a[x][y]) add(t1, t2, A);
				else add(t1, t2, B);
			}
}
void solve()
{
	int maxn = 0;
	for (int i = 1; i <= nn; i++) maxn = max(maxn, dijkstra(i));
	printf("%d", maxn);
}
int main()
{
	Input();
	get_edge();
	solve();
	return 0;
}

首发:2022-05-26 13:26:36

posted @ 2022-08-26 01:51  liangbowen  阅读(12)  评论(0编辑  收藏  举报