信息学奥赛一本通 4163:【GESP2512七级】城市规划 | 洛谷 P14921 [GESP202512 七级] 城市规划

【题目链接】

ybt 4163:【GESP2512七级】城市规划
洛谷 P14921 [GESP202512 七级] 城市规划

【题目难度】:E

【题目考点】

1. 图论:广搜 BFS

【解题思路】

"A 国有 n 座城市,城市之间由 m 条双向道路连接",表明每个城市是一个顶点,每条边是无向边,该图是无向图。

"任意一座城市均可经过若干条双向道路到达另一座城市",表明该图是连通图。
d ( u , v ) d(u,v) d(u,v)是从城市u出发到达城市v所需经过的双向道路的最少条数,就是无权图上顶点u到顶点v的最短路径长度(无权图上一条路径的长度为这条路径上的边数)

城市u的建设难度为它到其它城市的最大连通度,即为顶点u到其它各顶点最短路径中的最大值。无权图求单源最短路径问题时间复杂度最低的方法为广搜(BFS)。

从顶点u出发进行广搜,求出顶点u到其它顶点的最短路径长度,记录在 d i s dis dis数组, d i s i dis_i disi表示顶点 u u u到顶点 i i i的最短路径长度,求出 d i s dis dis数组的最大值,即为"城市u的建设难度"。

求出每个城市的"建设难度",记录于 a n s ans ans数组。即遍历所有顶点,假设访问到顶点 i i i,求从顶点 i i i出发的到其它顶点的最短路径的最大值,记录在 a n s i ans_i ansi。

最后求 a n s ans ans数组最小值的下标,即为建设难度最小的城市。

本题要求:"如果有多个满足条件的城市,则选取其中编号最小的城市",因此在求最小值下标时,如果遍历到与已知最小值相等的另一元素,则不更新最小值的下标。这样可以取到所有最小值中下标最小的最小值的下标。

每次广搜的时间复杂度为 O ( n + m ) O(n+m) O(n+m),其中 n n n为顶点数, m m m为边数,共需要进行 n n n次广搜,因此总体时间复杂度为 O ( n ( n + m ) ) O(n(n+m)) O(n(n+m)), n , m n,m n,m的最大值都为2000,当二者都取2000时,其数量级一致,因此 O ( n ( n + m ) ) = O ( n 2 ) O(n(n+m))=O(n^2) O(n(n+m))=O(n2), n 2 = 4000000 < 10 8 n^2=4000000<10^8 n2=4000000<108,该时间复杂度可以通过本题。

【题解代码】

解法1:广搜

  • 写法1:dis数组写法+vector邻接表
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2005;
int n, m, dis[N], ans[N]; 
bool vis[N];
vector<int> g[N];
int bfs(int sv)
{
	memset(vis, 0, sizeof(vis));
	int res = 0;//sv到其它顶点最短路径的最大值 
	queue<int> que;
	que.push(sv);
	dis[sv] = 0;
	vis[sv] = true;
	while(!que.empty())
	{
		int u = que.front();
		que.pop();
		res = max(res, dis[u]);//此时dis[u]的值已经确定,不再改变。求所有dis[u]的最大值 
		for(int v : g[u]) if(!vis[v])
		{
			vis[v] = true;
			dis[v] = dis[u]+1;
			que.push(v);
		}
	}
	return res;
}
int main()
{
	int u, v, mni = 1;
	cin >> n >> m;
	for(int i = 1; i <= m; ++i)
	{
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	for(int i = 1; i <= n; ++i)
		ans[i] = bfs(i);//i到其它顶点最短路径长度的最大值 
	for(int i = 1; i <= n; ++i) if(ans[i] < ans[mni])
		mni = i;
	cout << mni;
	return 0;
}
  • 写法2:结构体写法+链式前向星
cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 4005;
struct Path
{
	int v, d;
};
struct Edge
{
	int v, next;
} edge[N];
int n, m, ans[N], head[N], tot; 
bool vis[N];
void addEdge(int u, int v)
{
	int np = ++tot;
	edge[np].v = v;
	edge[np].next = head[u];
	head[u] = np;
}
int bfs(int sv)
{
	memset(vis, 0, sizeof(vis));
	int res = 0;//sv到其它顶点最短路径的最大值 
	queue<Path> que;
	que.push(Path{sv, 0});
	vis[sv] = true;
	while(!que.empty())
	{
		int u = que.front().v, d = que.front().d;
		que.pop();
		res = max(res, d);
		for(int i = head[u]; i != 0; i = edge[i].next)
		{
			int v = edge[i].v;
			if(!vis[v])
			{
				vis[v] = true;
				que.push(Path{v, d+1});
			}
		}
	}
	return res;
}
int main()
{
	int u, v, mni = 1;
	cin >> n >> m;
	for(int i = 1; i <= m; ++i)
	{
		cin >> u >> v;
		addEdge(u, v);
		addEdge(v, u);
	}
	for(int i = 1; i <= n; ++i)
		ans[i] = bfs(i);//i到其它顶点最短路径长度的最大值 
	for(int i = 1; i <= n; ++i) if(ans[i] < ans[mni])
		mni = i;
	cout << mni;
	return 0;
}
相关推荐
Simon_lca2 小时前
验厂不翻车!Acushnet 11 项核心政策 + 自查要点,一文搞定
大数据·人工智能·经验分享·算法·制造
不想写代码的星星2 小时前
C++ 的花括号有多狂?std::initializer_list 那些不讲武德的事儿
c++
elseif1232 小时前
初学者必背【考点清单(大全)】【上篇】
开发语言·c++·笔记·学习·循环结构·分支结构·考纲
并不喜欢吃鱼2 小时前
从零开始C++----二.(下篇)模版进阶与编译全过程的复习
开发语言·c++
智者知已应修善业2 小时前
【51单片机按键控制流水灯+数码管显示按键次数】2023-6-15
c++·经验分享·笔记·算法·51单片机
汉克老师2 小时前
GESP2023年12月认证C++三级( 第三部分编程题(1、小猫分鱼))
c++·算法·模拟算法·枚举算法·gesp三级·gesp3级
不知名的老吴2 小时前
View的三大特性之一:迟绑定
开发语言·c++·算法
小雅痞3 小时前
[Java][Leetcode hard] 135. 分发糖果
java·算法·leetcode
黎阳之光3 小时前
黎阳之光:全域实景立体管控,重构智慧电厂与变电站数字孪生新范式
大数据·人工智能·算法·安全·数字孪生