题目大意:
给你一张无向图,点数为N(N<=100),边数为M(M<=10000),起点为S,终点为一个集合End,且|End|=E,然后对于每条边,有5个参数,Ai,Bi,Ti,Ri,Pi,分别表示边i连在Ai,Bi间,假设你到边i的一端的时候已经走过的距离为D,那么你到达另一端的时间为Ri+(D+Ti)?Pi,令F[i]表示从S走到i的任意一条路径上走过的所有边中走过每条边所花费的时间的最大值最小是多少。我们令ans=min(F[i](i∈End)),如果ans<=H,则输出YES,并且输出ans,然后输出路径上的点数和路径上包含了那些点。
解题思路:
观察后我们可以发现,答案可以二分,那么我们就二分ans。
然后我们就只需要知道当ans=now时,我们只经过那些通过时间不超过now的边是否能够到达集合End中的一个点。
然后我们分析一下发现,如果我们在已经花费了T1时间到达a点,显然比在已经花费了T2时间到达a点要更有可能到达集合End,所以我们只需要SPFA最短路就行了。时间复杂度O(KE)。
AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
int N,M,H,S,EN;
struct bian_
{
int aim;
int next;
int T;
int R;
int P;
}bian[20010]={{0,0,0,0,0}};
int First[110]={0};
int ans=2e9;
int ansp=0;
int fa[110]={0};
int Out[110]={0};
int dist[110]={0};
int dui[810]={0};
int duip=0;
int hash[110]={0};
int E[110]={0};
void Add(int a,int b,int t,int r,int p,int k)
{
bian[k].next=First[a];
bian[k].aim=b;
bian[k].T=t;
bian[k].R=r;
bian[k].P=p;
First[a]=k;
return;
}
bool check(int Max)
{
memset(dist,-1,sizeof(dist));
duip=0;
dist[S]=0;
dui[++duip]=S;
for(int i=1;i<=duip;i++)
{
int u=dui[i];
for(int p=First[u];p!=0;p=bian[p].next)
{
int TT=dist[u]+bian[p].T;
int v=bian[p].aim;
if(dist[v]==-1) dist[v]=2147483647;
if((long long)TT*bian[p].P+bian[p].R<=(long long)Max && TT<dist[v])
{
fa[v]=u;
dist[v]=TT;
if(hash[v]==0)
{
hash[v]=1;
dui[++duip]=v;
}
}
}
hash[u]=0;
}
for(int i=1;i<=EN;i++)
{
if(dist[E[i]]!=2147483647 && dist[E[i]]!=-1)
{
ansp=0;
for(int j=E[i];j!=S;j=fa[j])
Out[++ansp]=j;
return true;
}
}
return false;
}
int main()
{
freopen("sgu240.in","r",stdin);
freopen("sgu240.out","w",stdout);
scanf("%d%d%d%d%d",&N,&M,&H,&S,&EN);
for(int i=1;i<=M;i++)
{
int a,b,t,r,p;
scanf("%d%d%d%d%d",&a,&b,&t,&r,&p);
Add(a,b,t,r,p,(i<<1)-1);
Add(b,a,t,r,p,i<<1);
}
for(int i=1;i<=EN;i++)
scanf("%d",&E[i]);
for(int L=0,R=H;L<=R;)
{
int mid=(L+R)>>1;
if(check(mid)==true)
{
ans=mid;
R=mid-1;
}
else L=mid+1;
}
if(ans==2e9)
cout<<"NO"<<endl;
else
{
cout<<"YES"<<endl;
cout<<ans<<endl;
cout<<ansp+1<<‘ ‘<<S;
for(int i=ansp;i>=1;i--)
printf(" %d",Out[i]);
cout<<endl;
}
fclose(stdin);
fclose(stdout);
return 0;
}
时间: 2024-11-04 19:03:58