spfa进阶使用二分+SLF(洛谷1951 收费站_NOI导刊2009提高)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spfa进阶使用二分+SLF(洛谷1951 收费站_NOI导刊2009提高)相关的知识,希望对你有一定的参考价值。

在某个遥远的国家里,有n个城市。编号为1,2,3,…,n。

这个国家的政府修建了m条双向的公路。每条公路连接着两个城市。沿着某条公路,开车从一个城市到另一个城市,需要花费一定的汽油。

开车每经过一个城市,都会被收取一定的费用(包括起点和终点城市)。所有的收费站都在城市中,在城市间的公路上没有任何的收费站。

小红现在要开车从城市u到城市v(1<=u,v<=n)。她的车最多可以装下s升的汽油。在出发的时候,车的油箱是满的,并且她在路上不想加油。

在路上,每经过一个城市,她都要交一定的费用。如果某次交的费用比较多,她的心情就会变得很糟。所以她想知道,在她能到达目的地的前提下,她交的费用中最多的一次最少是多少。这个问题对于她来说太难了,于是她找到了聪明的你,你能帮帮她吗?

输入格式:

第一行5个正整数,n,m,u,v,s,分别表示有n个城市,m条公路,从城市u到城市v,车的油箱的容量为s升。

接下来的有n行,每行1个整数,fi表示经过城市i,需要交费fi元。

再接下来有m行,每行3个正整数,ai,bi,ci(1<=ai,bi<=n),表示城市ai和城市bi之间有一条公路,如果从城市ai到城市bi,或者从城市bi到城市ai,需要ci升的汽油。

输出格式:

仅一个整数,表示小红交费最多的一次的最小值。

如果她无法到达城市v,输出-1.

输入样例#1:
4 4 2 3 8
8
5
6
10
2 1 2
2 4 1
1 3 4
3 4 3
输出样例#1:
8
  1 #include<iostream>
  2 #include<algorithm>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<queue>
  7 #define maxn 150000
  8 #define LL long long
  9 
 10 using namespace std;
 11 LL  n,m,u,v,s;
 12 
 13 struct Edge
 14 {
 15    LL  next,to,w;
 16 };
 17 struct Edge edge[maxn];
 18 LL  cnt=0;
 19 LL  head[maxn];
 20 LL val[maxn];
 21 
 22 void add(LL  u,LL  v,LL  ww)
 23 {
 24     edge[++cnt].to=v;
 25     edge[cnt].w=ww;
 26     edge[cnt].next=head[u];
 27     head[u]=cnt;
 28 }
 29 
 30 deque<LL> q;//双向队列 
 31 LL  book[maxn],dis[maxn];
 32   
 33 int  spfa(LL  x)//最大的价值 
 34 {
 35        if(val[u]>x||val[v]>x) return 0;//剪枝   
 36        memset(book,0,sizeof(book));
 37        
 38         for(LL  i=1;i<=n;i++)
 39              dis[i]=1e12;
 40              
 41           book[u]=1;dis[u]=0;
 42           q.push_back(u);
 43           
 44           while(!q.empty())
 45           {
 46               LL  fr=q.front();
 47               book[fr]=0;q.pop_front();
 48               for(LL i=head[fr];i;i=edge[i].next)
 49               {
 50                    LL  j=edge[i].to;
 51                    if(val[j]>x) continue;
 52                    if(dis[j]>dis[fr]+edge[i].w)
 53                    {
 54                        dis[j]=dis[fr]+edge[i].w;
 55                        if(!book[j])
 56                        {
 57                            if(q.empty()) q.push_back(j);
 58                            else
 59                            {
 60                               if(dis[j]<dis[q.front()])
 61                                   q.push_front(j);//在前部插入
 62                                  else
 63                                    q.push_back(j); 
 64                            }
 65                            book[j]=1;//标记已经入队 
 66                        }
 67                    }
 68               }
 69           }
 70           if(dis[v]<=s) return 1;
 71          return 0;
 72 }  
 73 
 74 
 75 int  main()
 76 {     LL  l=1,r=0;
 77     cin>>n>>m>>u>>v>>s;
 78     for(LL  i=1;i<=n;i++)
 79     {
 80        cin>>val[i]; 
 81        r=max(val[i],r);
 82     }  
 83        LL  t1,t2,t3;
 84     for(LL  i=1;i<=m;i++)
 85     {
 86        cin>>t1>>t2>>t3;
 87        add(t1,t2,t3);
 88        add(t2,t1,t3);
 89     }
 90     if(!spfa(1e13))
 91     {
 92       cout<<-1;
 93       return 0;
 94     }
 95     while(l<=r)
 96     {
 97         LL  mid=(l+r)>>1;
 98         if(spfa(mid))r=mid-1;
 99         else l=mid+1;
100     }
101     cout<<l<<endl;
102    return 0;
103 }

90分的代码,还需要优化

以上是关于spfa进阶使用二分+SLF(洛谷1951 收费站_NOI导刊2009提高)的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P1462 通往奥格瑞玛的道路 二分答案+最短路SPFA

洛谷 P1462 通往奥格瑞玛的道路(spfa+二分搜索)(4boy)

SPFA的两个优化:SLF与LLL

洛谷P1462 通往奥格瑞玛的道路[二分答案 spfa 离散化]

洛谷P1462二分+堆优化dij

洛谷 [P1426] 通往奥格瑞玛的道路