最大化最短路

给定一个 n 个点 m 条边的无向连通图。

图中所有点的编号为 1∼n。

图中不含重边和自环。

指定图中的 k 个点为特殊点。

现在,你必须选择两个特殊点,并在这两个点之间增加一条边。

所选两点之间允许原本就存在边。

我们希望,在增边操作完成以后,点 1 到点 n 的最短距离尽可能大。

输出这个最短距离的最大可能值。

注意,图中所有边(包括新增边)的边长均为 1。

输入格式
第一行包含三个整数 n,m,k。

第二行包含 k 个整数 a1,a2,…,ak,表示 k 个特殊点的编号,ai 之间两两不同。

接下来 m 行,每行包含两个整数 x,y,表示点 x 和点 y 之间存在一条边。

输出格式
一个整数,表示最短距离的最大可能值。

数据范围
前六个测试点满足 2≤n≤100。
所有测试点满足 2≤n≤2×10^5,n−1≤m≤2×10^5,2≤k≤n,1≤ai≤n,1≤x,y≤n。

输入样例1:
5 5 3
1 3 5
1 2
2 3
3 4
3 5
2 4
输出样例1:
3
输入样例2:
5 4 2
2 4
1 2
2 3
3 4
4 5
输出样例2:
3

【分析】

算法:bfs

因为边的权值为1,所以使用bfs求最短路;
针对每个点,求出到1到所有点i的最短距离为dist1[i]、n到所有点i的最短距离dist2[i]
接着对两个选择点进行讨论。根据是否在最短路径上可以分为两类:
  1. 两个点不在最短路上面,答案还是dist1[n]
  2. 两个点在最短路上,设两点为x,y,那么就有如下两种情况:
      ① 最短路径可能是1—>x, x—>y, y—>n。答案:dist1[x]+1+dist2[y]
      ② 最短路径可能是1—>y, y—>x, x—>n。答案:dist1[y]+1+dist2[x]

参考代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5, M = 2 * N;
struct node{
	int to,next;
}e[M]; 
int h[N], cnt=0;
int n, m, k, q[N], tt, hh, p[N], dis1[N], dis2[N];
void add(int a, int b){
	e[++cnt].to = b, e[cnt].next = h[a], h[a] = cnt; 
}
void bfs(int st, int dis[]) {
    memset(dis, 0x3f, 4*N);
    dis[st] = 0;
    queue<int> q;
    q.push(st);
    while (!q.empty()) {
        int t = q.front();
        q.pop();
        for (int i = h[t]; i; i = e[i].next) {
            int j = e[i].to;
            if (dis[j] > dis[t] + 1) { 
				dis[j] = dis[t] + 1;
				q.push(j); 
			}
        }
    }
}
bool cmp(int a, int b) {
    return dis1[a] + dis2[b] < dis1[b] + dis2[a];
}
int main() {
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 0; i < k; i++) scanf("%d", &p[i]);
    int a, b;
    while (m--) {
        scanf("%d%d", &a, &b);
        add(a, b), add(b, a);
    }
    bfs(1, dis1);
	bfs(n, dis2);
    sort(p, p + k, cmp);
    int res = 0, maxv = dis1[p[0]]; //res记录最大距离 
    for (int i = 1; i < k; i++) {
        res = max(res, maxv + dis2[p[i]] + 1);
        maxv = max(maxv, dis1[p[i]]);
    }
    printf("%d", min(res, dis1[n]));
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值