【二分答案&&最短路】URAL - 2034 Caravans

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值