【二分答案&&最短路】URAL

来源:互联网 发布:淘宝站外推广怎么做 编辑:程序博客网 时间:2024/06/05 09:24

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 0x3f3f3f3fstruct 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;}
原创粉丝点击