Problem Description
给你n个点,m条边。接下来m行每行u, v代表u 可以到达v,边权为1。最后一行输入s,f,r。代表s到f的所有最短路中。让你求r到这些最短路中最小值的最大值。(r到这些最短路的距离是最小值。但是因为有很多条最短路,所以找出到这些条最短路的最大值)
思路:
先求出s-f的最短路的值res。在求出r到各个点的最短路。这时候二分答案。从1-n查找答案。假设答案是mid 那么s到f的过程中,在不经过距离r的距离为(mid - 1)的结点的时候,s-f的最短路还是res。如果不满足缩小mid.满足增加mid.
#include<bits/stdc++.h>
using namespace std;
#define mm 100055
#define inf 0x3f3f3f3f
struct node
{
int to, w, next;
};
node Map[2 * mm];
int head[mm], vis[mm], dist[mm];
int del[mm], dis[mm];//分别用来记录该点能不能走。r到各个点的最小值
int s, f, r, n, res;
int spfa(int u, int v)//求最短路
{
memset(vis, 0, sizeof(vis));
memset(dist, inf, sizeof(dist));
if(del[u]) return inf;//如果为真,不能走(因为r到该点的距离小于mid)
dist[u] = 0;
queue<int> q;
q.push(u);
while(!q.empty())
{
u = q.front(); q.pop();
vis[u] = 0;
for(int i = head[u]; ~i; i = Map[i].next)
{
int to = Map[i].to, w = Map[i].w;
if(dist[to] > dist[u] + w && !del[to])
{
dist[to] = dist[u] + w;
if(!vis[to])
{
vis[to] = 1;
q.push(to);
}
}
}
}
return dist[v];
}
bool check(int mid)
{
memset(del, 0, sizeof(del));//初始化
for(int i = 1; i <= n; i++)
{
del[i] = dis[i] < mid;//dis[i] < mid 为真,真代表不能走
}
return spfa(s, f) == res;//满足返回真
}
void add(int u, int v, int w, int &cnt)//前向星存图
{
Map[cnt].to = v;
Map[cnt].w = w;
Map[cnt].next = head[u];
head[u] = cnt++;
}
int main()
{
int m, u, v;
while(~scanf("%d %d", &n, &m))
{
int cnt = 0;
memset(head, -1, sizeof(head));//初始化
while(m--)//双向
{
scanf("%d %d", &u, &v);
add(u, v, 1, cnt);
add(v, u, 1, cnt);
}
scanf("%d %d %d", &s, &f, &r);
memset(del, 0, sizeof(del));
spfa(r, s);//求出r到各个点的最短路
memcpy(dis, dist, sizeof(dist));
memset(del, 0, sizeof(del));
res = spfa(s, f);//求出s-f最短路的值
int l = 0, r = n, mid;
while(l <= r)//二分答案
{
mid = (l + r) / 2;
if(check(mid))//满足
{
l = mid + 1;//mid值得增加
}
else r = mid - 1;//不满足mid值减少
}
if(l)//输出
printf("%d\n", l - 1);
else printf("%d\n", l);
}
return 0;
}