1. 程式人生 > >[LGOJ]P1462通往奧格瑞瑪的道路[二分答案]

[LGOJ]P1462通往奧格瑞瑪的道路[二分答案]

lse printf 目標 push 輸出 就是 十年 char ret

這道題要求最大收費點的最小值,明顯是二分答案
二分check(maxf)函數目標:判斷能否在 最大收費點小於maxf 的條件下,走到終點
能則縮小maxf, 否則只能是更大的maxf
具體實現: dijkstra松弛的時候加個判斷 點權小於maxf 就行了

#include<cstdio>
#include<queue>
#define re register
#define int long long
//十年競賽一場空
//沒開longlong見祖宗
//總有你想不到的地方炸了int
using namespace std;
inline int read()
{
    int s=0,b=1;
    char ch;
    do{
        ch=getchar();
        if(ch=='-') b=-1;
    }while(ch<'0' || ch>'9');
    while(ch>='0' && ch<='9')
    {
        s=s*10+ch-'0';
        ch=getchar();
    }
    return b*s;
}//快讀是不可能出鍋的
struct edge{
    int t,w,next;
}e[510000];
int head[110000],cnt=0,n,m,b,f[110000];
//十年競賽一場空
//數組開小見祖宗
//別吝嗇空間!
//總有你想不到的地方炸了你的數組
inline void add(int f,int t,int w)
{
    //printf("%lld\n",cnt);
    //十年競賽一場空
    //不刪DeBug見祖宗
    ++cnt;
    e[cnt].t=t;
    e[cnt].w=w;
    e[cnt].next=head[f];
    head[f]=cnt;
}
struct node{
    int dis,num;
    bool operator < (const node & t)const
        {
            return dis>t.dis;
        }
};
priority_queue<node> q;
int dis[11000];
bool dijkstra(int maxf) //返回路徑上每個點的權值小於maxf時, 能否走到終點
{
    //標準dijkstra, 只是在松弛時加入了節點的權值不能超過maxf的條件
    //這樣就可以保證求出 經過的節點的權值都不超過maxf 條件下的最短路
    if(f[1]>maxf) return false; //註意題目說起點也要算花費
    for(re int i=1;i<=n;i++) dis[i]=2147483647;
    node x;
    x.num=1;
    x.dis=0;
    dis[1]=0;
    q.push(x);
    while(!q.empty())
    {
        x=q.top();
        q.pop();
        int u=x.num;
        if(x.dis!=dis[u]) continue;
        for(re int i=head[u];i;i=e[i].next)
        {
            int v=e[i].t,w=e[i].w;
            if(dis[u]+w<dis[v] && f[v]<=maxf)
            {
                dis[v]=dis[u]+w;
                node x1;
                x1.num=v;
                x1.dis=dis[v];
                q.push(x1);
            }
        }
    }
    if(dis[n]>=b) return false;
    //如果求出來1到n的最短路長度大於血量
    //則不能做到使 路徑上每個點的權值都不超過maxf
    else return true;
}
signed main()
{
    n=read();
    m=read();
    b=read();
    int x,y,z;
    int l=2147483647,r=0;
    for(re int i=1;i<=n;++i)
    {
        f[i]=read();
        if(f[i]<l) l=f[i];
        if(f[i]>r) r=f[i];
    }//預處理出二分的區間:最小點權~最大點權
    for(re int i=1;i<=m;++i)
    {
        x=read();
        y=read();
        z=read();
        add(x,y,z);
        add(y,x,z);
        //註意是無向圖
    }
    if(!dijkstra(2147483647)){
        printf("AFK\n");
        //無限制的情況下,如果不能從起點走到終點,肯定輸出 啊♂FUCK
        return 0;
    }
    //下面就是標準二分
    while(l<r)
    {
        int mid=(l+r)/2;
        if(!dijkstra(mid)) l=mid+1;
        else r=mid;
    }
    printf("%lld\n",l);
    return 0;
}

[LGOJ]P1462通往奧格瑞瑪的道路[二分答案]