刚开始以为可以二分…
实际上是没有单峰性的。
考虑每条边都加一个整数,那么肯定是使
s
到
用DP算出经过
i
个点到达
如果经过
i
个点不能到
枚举 fi,t ,如果存在 gj,t,j<i 满足 gj,t<fi,t ,那么就Impossible
当 fi,t≠inf 且任意 j<i , gj,t=inf ,那么就Infinity
否则能加
min{gj,t−fi,ti−j|j<i}
再判断下加上后这条路是不是最短的就可以了。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
const int N=1010;
const ll inf=1e18;
int T,n,m,s,t,cnt,k,a[N],G[N];
struct edge{
int t,nx;
ll w;
}E[N*20];
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void rea(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
inline void addedge(int x,int y,int z){
E[++cnt].t=y; E[cnt].nx=G[x]; E[cnt].w=z; G[x]=cnt;
E[++cnt].t=x; E[cnt].nx=G[y]; E[cnt].w=z; G[y]=cnt;
}
ll f[N][N],g[N][N];
int main(){
rea(T);
while(T--){
rea(n); rea(m); rea(s); rea(t);
memset(G,0,sizeof(G)); cnt=0;
memset(a,0,sizeof(a));
for(int i=1,x,y,c;i<=m;i++)
rea(x),rea(y),rea(c),addedge(x,y,c);
rea(k);
for(int i=1,x;i<=k;i++) rea(x),a[x]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=n;j++) f[i][j]=g[i][j]=inf;
f[s][0]=g[s][0]=0;
for(int i=0;i<n;i++)
for(int j=1;j<=n;j++)
if(f[j][i]<inf && a[j])
for(int k=G[j];k;k=E[k].nx)
f[E[k].t][i+1]=min(f[E[k].t][i+1],f[j][i]+E[k].w);
for(int i=0;i<n;i++)
for(int j=1;j<=n;j++)
if(g[j][i]<inf)
for(int k=G[j];k;k=E[k].nx)
g[E[k].t][i+1]=min(g[E[k].t][i+1],g[j][i]+E[k].w);
ll ans=-1;
for(int i=1;i<=n;i++){
if(f[t][i]==inf) continue;
int j;
for(j=1;j<=i;j++)
if(g[t][j]<f[t][i]) break;
if(j<=i) continue;
for(j=1;j<i;j++) if(g[t][j]!=inf) break;
if(j>=i){
ans=inf; break;
}
ll cur=inf;
for(j=1;j<i;j++)
cur=min(cur,(-f[t][i]+g[t][j])/(i-j));
for(j=i+1;j<=n;j++)
if(f[t][i]+i*cur>g[t][j]+j*cur) break;
if(j<=n) continue;
ans=max(ans,cur);
}
if(ans==-1) puts("Impossible");
else if(ans==inf) puts("Infinity");
else cout<<ans<<endl;
}
}