题意
给出一个无向图,问从1到n是否存在一条长度为L的路径。
n,m<=50,1<=路径长度<=10000,L<=10^18
分析
考虑枚举起点的每一条出边,设其权值为w,那么我们把w*2当作模数,建立n*w*2个新点,dis[i,j]表示我走到点i路径权值模w*2等于j时的最短路径是多少,然后直接跑最短路。如果dis[n,L%(w*2)]<=L那么就表示一定可以找到一条长度为L的路径。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const int N=55;
const LL inf=2000000000000000000;
int n,m,cnt,last[N];
LL L,dis[N][20005];
bool vis[N][20005];
struct edge{int to,w,next;}e[N*2];
queue<pair<int,int> > que;
void addedge(int u,int v,int w)
{
e[++cnt].to=v;e[cnt].w=w;e[cnt].next=last[u];last[u]=cnt;
e[++cnt].to=u;e[cnt].w=w;e[cnt].next=last[v];last[v]=cnt;
}
void spfa(int mo)
{
que.push(make_pair(1,0));vis[1][0]=1;
while (!que.empty())
{
pair<int,int> u=que.front();que.pop();
int x=u.first,y=u.second;
for (int i=last[x];i;i=e[i].next)
if (dis[x][y]+e[i].w<dis[e[i].to][(y+e[i].w)%mo])
{
int x1=e[i].to,y1=(y+e[i].w)%mo;
dis[x1][y1]=dis[x][y]+e[i].w;
if (!vis[x1][y1]) que.push(make_pair(x1,y1)),vis[x1][y1]=1;
}
vis[x][y]=0;
}
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d%d%lld",&n,&m,&L);
cnt=0;memset(last,0,sizeof(last));
for (int i=1;i<=m;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
addedge(x+1,y+1,w);
}
int flag=0;
for (int i=1;i<=cnt;i+=2)
if (e[i].to==1||e[i+1].to==1)
{
int w=e[i].w*2;
for (int j=1;j<=n;j++)
for (int k=0;k<w;k++) dis[j][k]=inf;
dis[1][0]=0;
spfa(w);
if (dis[n][L%w]<=L)
{
puts("Possible");flag=1;
break;
}
}
if (!flag) puts("Impossible");
}
return 0;
}