洛谷P1462-通往奥格玛瑞的路【日常图论,二分查找,最短路,SPAF】

前言

这道题感谢朋友的帮助,这里是他的博客地址:
http://blog.csdn.net/sugar_free_mint


题目

一个无向图,每个点和边都有一定的权值,要求从点1到点2在经过边的权值小于b的情况下经过点的最大权值尽量小

输入

4 4 8(4个点,4条边,要求边的权值小于8)
8(第一个点的权值)
5
6
10
2 1 2(2到1有条边权值为2)
2 4 1
1 3 4
3 4 3

输出

10


解题思路

先看看能否到达,不然输出AFK。然后如果可以,用二分法找最优答案


代码

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct woc{
    int w,x,y,next;
};//邻接表
woc a[100001];
int n,m,b,xx,yy,ww,ls[10001],head,tail,cost[10001],t,state[10001];
bool v[10001];
long long f[10001];
bool spfa(int money)//如果经过点权值小于money,是否可以到达
{
    memset(f,127/3,sizeof(f));//初始化
    if (cost[1]>money) return false;//没用
    head=0;
    tail=1;
    v[1]=true;
    state[1]=1;
    f[1]=0;//初始化
    while (head!=tail)
    {
        head++;//入队
        head=(head-1)%n+1;//循环队列
        t=ls[state[head]];//联通该点的一条边
        while (t!=0)
        {
            if (f[a[t].x]+a[t].w<f[a[t].y])
            {
                f[a[t].y]=f[a[t].x]+a[t].w;
                if (!v[a[t].y] && cost[a[t].y]<=money)//看看点是否满足要求
                {
                    tail++;//入队
                    tail=(tail-1)%n+1;//循环队列
                    state[tail]=a[t].y;
                    v[a[t].y]=true;//标记
                }
            }
            t=a[t].next;//下一条边
        }
        v[state[head]]=false;//解封
    }
    if (f[n]<b) return true;
    return false;//返回结果
}
int main()
{
    int u=0,mid,l,r;
    scanf("%d%d%d",&n,&m,&b);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&cost[i]);
        r=max(r,cost[i]);
    }
    l=max(cost[1],cost[n]);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&xx,&yy,&ww);
        a[++u].x=xx;
        a[u].y=yy;
        a[u].w=ww;
        a[u].next=ls[xx];
        ls[xx]=u;
        a[++u].y=xx;
        a[u].x=yy;
        a[u].w=ww;
        a[u].next=ls[yy];
        ls[yy]=u;//无向图
    }
    if (!spfa(1000000001)) {printf("AFK");return 0;}
    //是否可以到达
    while (l<=r)
    {
        mid=(l+r)/2;//二分
        if (spfa(mid)) r=mid-1;
        else l=mid+1;
    }
    printf("%d",l);//输出
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值