题目:https://www.luogu.org/problemnew/show/1951
题目描述
在某个遥远的国家里,有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.
输入输出样例
4 4 2 3 8 8 8 5 6 10 2 1 2 2 4 1 1 3 4 3 4 3
说明
【数据规模】
对于60%的数据,满足n<=200,m<=10000,s<=200
对于100%的数据,满足n<=10000,m<=50000,s<=1000000000
对于100%的数据,满足ci<=1000000000,fi<=1000000000,可能有两条边连接着相同的城市。
解析
看到1000000000顿时感到很害怕,但后来发现这是边权。
想了一会,没啥思路,orz。
但看到1000000000这个貌似没用的数据,于是想到:如果没用出题人告你干啥,还整得这么大。
这么大,只有二分了啊。。。。。。
好了,二分最大费用,跑spfa。美滋滋地过了样例,然后美滋滋地提交,然后。。。。。。
spfa大暴力代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<vector> 7 #include<queue> 8 using namespace std; 9 #define ll long long 10 struct line{ 11 ll from,to; 12 ll d; 13 }; 14 vector<line> edge; 15 vector<ll> G[10010]; 16 ll n,m,s,e,V; //s start e end v rongliang 17 ll v[10010]; 18 ll ra,rb,rc; 19 ll l,r,mid,ans; 20 ll dis[10010]; 21 bool vis[10010]; 22 void addedge(ll from,ll to,ll val){ 23 edge.push_back((line){from,to,val}); 24 int m=edge.size(); 25 G[from].push_back(m-1); 26 } 27 bool check(ll maxv){ 28 if (maxv<v[s]) return false; 29 memset(dis,0x3f,sizeof(dis)); 30 memset(vis,false,sizeof(vis)); 31 queue<ll> q; 32 q.push(s); 33 vis[s]=true; 34 dis[s]=0; 35 while (!q.empty()){ 36 int x=q.front(); 37 q.pop(); 38 vis[x]=false; 39 for (ll i=0;i<G[x].size();++i){ 40 ll to=edge[G[x][i]].to; 41 ll val=edge[G[x][i]].d; 42 if (v[to]>maxv) continue; 43 if (dis[to]>dis[x]+val){ 44 dis[to]=dis[x]+val; 45 if (!vis[to]){ 46 vis[to]=true; 47 q.push(to); 48 } 49 } 50 } 51 } 52 if (dis[e]>V) return false; 53 return true; 54 } 55 int main(){ 56 scanf("%lld%lld%lld%lld%lld",&n,&m,&s,&e,&V); 57 for (ll i=1;i<=n;++i){ 58 scanf("%lld",&v[i]); 59 } 60 for (ll i=1;i<=m;++i){ 61 scanf("%lld%lld%lld",&ra,&rb,&rc); 62 addedge(ra,rb,rc); 63 addedge(rb,ra,rc); 64 } 65 l=0; r=1000000000; 66 while (l<=r){ 67 mid=(l+r)>>1; 68 if (check(mid)){ 69 ans=mid; 70 r=mid-1; 71 }else{ 72 l=mid+1; 73 } 74 } 75 printf("%d",ans); 76 return 0; 77 }
哇无良出题人卡spfa啊啊啊orz。
没办法,上迪杰斯特拉吧。
我把-1吃了orz。
最后,终于ac。
考试前老师出问题orz。
代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<vector> 7 #include<queue> 8 using namespace std; 9 #define ll long long 10 struct line{ 11 ll from,to; 12 ll d; 13 }; 14 vector<line> edge; 15 vector<ll> G[10010]; 16 struct node{ 17 ll pos,d; 18 bool operator < (const node &x)const{ 19 return d>x.d; 20 } 21 }uu,vv; 22 priority_queue<node> que; 23 ll n,m,s,e,V; //s start e end v rongliang 24 ll v[10010]; 25 ll ra,rb,rc; 26 ll l,r,mid,ans; 27 ll dis[10010]; 28 bool vis[10010]; 29 ll index_[10010],tot; 30 void addedge(ll from,ll to,ll val){ 31 edge.push_back((line){from,to,val}); 32 int m=edge.size(); 33 G[from].push_back(m-1); 34 } 35 bool check(ll maxv){ 36 if (maxv<v[s]) return false; 37 memset(dis,0x3f,sizeof(dis)); 38 memset(vis,false,sizeof(vis)); 39 while (!que.empty()) que.pop(); 40 dis[s]=0; 41 que.push((node){s,0}); 42 while (!que.empty()){ 43 uu=que.top(); que.pop(); 44 if (vis[uu.pos]) continue; 45 vis[uu.pos]=true; 46 for (ll i=0;i<G[uu.pos].size();++i){ 47 ll to=edge[G[uu.pos][i]].to; 48 ll val=edge[G[uu.pos][i]].d; 49 if (v[to]>maxv) continue; 50 if (dis[to]<=dis[uu.pos]+val) continue; 51 dis[to]=dis[uu.pos]+val; 52 que.push((node){to,dis[to]}); 53 } 54 } 55 return dis[e]<=V; 56 } 57 int main(){ 58 scanf("%lld%lld%lld%lld%lld",&n,&m,&s,&e,&V); 59 for (ll i=1;i<=n;++i){ 60 scanf("%lld",&v[i]); 61 index_[i]=v[i]; 62 } 63 for (ll i=1;i<=m;++i){ 64 scanf("%lld%lld%lld",&ra,&rb,&rc); 65 addedge(ra,rb,rc); 66 addedge(rb,ra,rc); 67 } 68 sort(index_+1,index_+1+n); 69 tot=unique(index_+1,index_+1+n)-(index_+1); 70 l=1; r=tot; 71 if (!check(index_[r])){ 72 printf("-1"); 73 return 0; 74 } 75 while (l<=r){ 76 mid=(l+r)>>1; 77 if (check(index_[mid])){ 78 ans=index_[mid]; 79 r=mid-1; 80 }else{ 81 l=mid+1; 82 } 83 } 84 printf("%d",ans); 85 return 0; 86 }