题目描述
是一个爱旅游的探险家,也是一名强迫症患者。现在
想要在
国进行一次长途旅行,C国拥有n个城市(编号为
),城市之间有
条道路,可能某个城市到自己有一条道路,也有可能两个城市之间有多条道路,通过每条道路都要花费一些时间。
从0号城市开始出发,目的地为
号城市。由于
想要好好参观一下C国,所以
想要旅行恰好
小时。为了让自己的旅行更有意思,
决定不在任何一个时刻停留(走一条到城市自己的路并不算停留)。
想知道是否能够花恰好T小时到达
号城市(每个城市可经过多次)。现在这个问题交给了你。
若可以恰好到达输出“
”否则输出“
”。(不含引号)。
输入格式
第一行一个正整数
,表示数据组数。
每组数据第一行
个整数,分别为
。
接下来
行,每行
个整数
,代表城市
和城市
之间有一条耗时为
的双向边。
输出格式
对于每组数据输出” ”或者” ”.
数据范围
30%:
另有
30%:
100%:
Solutiuon
前言
之所以拿出这道题,因为这是一道非常好的模板题。
30opt
算是容易想到。用 表示到达 位置用了 时间。实际上就是对一个点分成很多不同的状态,然后把一个状态看成一个点加入队列用SPFA的思想 看是否能到达就可以了。
100opt
注意到
值巨大,不得不优化一下算法。我们发现对于
来说,到达
的时间一定是j.显然有大部分状态没有用。我们发现如果到达i时有这样两个时间
和
,这两种时间显然都是合法的,也就是有一种走法可以实现的 ,那么如果这个k值有特殊意义的话,那么此题很好办。如果这个
值可以在任何一种走法中加入若干次,那么如果到达一个点存在一种走法使得到这点的时间为
,那么一定有走法使得到这点时间为
,因为
可以任意加入,那么,这样的
是什么?
k一定可以是从起点出发的,然后回到起点的一个环的长度。这样的合法性显然。
清楚了这个,如果
合法,那么
合法。
那么这些就没有必要存储了。进而推知,只需存储
的状态。这样相当于把之前所有的
都转化成了
。那么这样的转移会有错误吗?实际上由于取模运算具有较强的灵活性,
整体取模
与
取模k是一样的,所以转移式
仔细研究转移式, 的值一定可以写成 的形式,所以 的值越小越优,越能证明他能达到比他大 的时间.所以此处需套用最短路的模板.
接下来,判断一下能否在终点到达 时刻.我们知道如果能够,那么一定 有值,这个值又可以写成 , 也可以写成 ,如果这个值小于T,也就是 那么一定可以在T时刻走到n点.
总结一下
实际上就是一个压缩状态的问题
代码
特别鸣谢YSN巨佬提供AC代码
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#define ll long long
#define re register
#define il inline
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=500,mod=10000;
int T,n,m,cnt,h[N],f=0,ysn,d;
ll t,dp[20005][105];
bool vis[20005][105];
struct Edge{int to,nxt,w;}e[N<<1];
il void add(re int u,re int v,re int w){e[++cnt]=(Edge){v,h[u],w};h[u]=cnt;}
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il void wri(re int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) wri(x/10);
putchar(x%10+'0');
}
struct node{int u,len,w;bool operator < (const node &o) const {return w>o.w;}};
priority_queue<node>Q;
il void SPFA()
{
memset(dp,63,sizeof(dp));memset(vis,0,sizeof(vis));
Q.push((node){1,0,0});dp[0][1]=0;
while(!Q.empty())
{
re node now=Q.top();Q.pop();re int u=now.u,len=now.len%d,w=now.w;
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to,lenn=(len+e[i].w)%d;
if(dp[lenn][v]>dp[len][u]+e[i].w)
{
dp[lenn][v]=dp[len][u]+e[i].w;
if(!vis[lenn][v]) vis[lenn][v]=1,Q.push((node){v,lenn,dp[lenn][v]});
}
}
vis[len][u]=0;
}
}
int main()
{
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
T=gi();
while(T--)
{
n=gi();m=gi();t=gi();
memset(h,-1,sizeof(h));cnt=0;
fp(i,1,m)
{
re int u=gi()+1,v=gi()+1,w=gi();
add(u,v,w);add(v,u,w);
}
d=1e9;
for(re int i=h[1];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(v^1) d=min(d,e[i].w);
}
d<<=1;
//d=1;
SPFA();
puts(dp[t%d][n]<=t?"Possible":"Impossible");
}
fclose(stdin);
fclose(stdout);
return 0;
}