CodeForces-1307Dカウアンドフィールズ
元のタイトルの住所:
http://codeforces.com/contest/1307/problem/D
トピック:
無向グラフと一連の点の場合、これらの点のいずれか2つを選択してエッジを接続し、1の最短経路を1 —> nに最大にします。最大の最短経路はどれかを尋ねます。
基本的な考え方:
最初に1からこれらのポイントまでの最短パスをbfsで2回見つけ、配列dis1に記録します; nからこれらのポイントまでの最短パスを配列dis2に記録します;
次にエッジのペア1-> nの場合道路には影響があります。つまり、エッジを接続した後の最大最短パスが元の最短パスよりも大きい場合、答えはエッジを接続した後の最大最短パスです。それ以外の場合は、元の最短パスが使用されます。
エッジを接続した後の最大最短パスを見つける方法を検討します。最大最短パスはmax(min(dis1 [a] + dis2 [b] +1、dis1 [b] + dis2 [a] + 1))(a、bは前述のポイントの2つ)、dis1 [a] + dis2 [b] <= dis2 [b] + dis1 [a]と仮定することもできます。その場合、dis1 [a] + dis2 [b]を見つけるだけで済みます。シフト不等式の最大値は、dis1 [a] -dis2 [a] <= dis1 [b] -dis2 [b]この順序に従って、毎回更新される最大のdis1 [a]を列挙し、更新します。答えは、dis1 [a] + dis2 [b] + 1です。
最後に、元の最短経路と比較してください。
実装コード:
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false)
#define int long long
#define INF 0x3f3f3f3f
const int maxn = 2e5+10;
int n,m,k;
int a[maxn];
int dis1[maxn],dis2[maxn];
vector<int> G[maxn];
void bfs(int *dis,int s) {
fill(dis, dis + n + 1, INF);
queue<int> q;
q.push(s);
dis[s] = 0;
while (!q.empty()) {
int v = q.front();
q.pop();
for (auto it : G[v]) {
if (dis[it] == INF) {
dis[it] = dis[v] + 1;
q.push(it);
}
}
}
}
struct Node {
int x, y;
Node(int _x, int _y) { x = _x, y = _y; }
bool operator<(const Node &no) const {
return x < no.x;
}
};
vector<Node> memo;
signed main() {
IO;
cin >> n >> m >> k;
for (int i = 0; i < k; i++) cin >> a[i];
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
bfs(dis1, 1);
bfs(dis2, n);
for (int i = 0; i < k; i++) memo.emplace_back(Node(dis1[a[i]] - dis2[a[i]], a[i]));
sort(memo.begin(), memo.end());
int ans = 0;
int mx = -INF;
for (auto it : memo) {
ans = max(ans, mx + dis2[it.y] + 1);
mx = max(mx, dis1[it.y]);
}
ans = min(ans, dis1[n]);
cout << ans << endl;
return 0;
}