【题目链接】
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;
}