題目描述
JY是一個愛旅遊的探險家,也是一名強迫症患者。現在JY想要在C國進行一次長途旅行,C國擁有n個城市(編號爲0,1,2...,n - 1),城市之間有m條道路,可能某個城市到自己有一條道路,也有可能兩個城市之間有多條道路,通過每條道路都要花費一些時間。JY從0號城市開始出發,目的地爲n – 1號城市。由於JY想要好好參觀一下C國,所以JY想要旅行恰好T小時。爲了讓自己的旅行更有意思,JY決定不在任何一個時刻停留(走一條到城市自己的路並不算停留)。JY想知道是否能夠花恰好T小時到達n – 1號城市(每個城市可經過多次)。現在這個問題交給了你。若可以恰好到達輸出“Possible”否則輸出“Impossible”。(不含引號)。
輸入格式
第一行一個正整數Case,表示數據組數。每組數據第一行3個整數,分別爲n, m, T。
接下來m行,每行3個整數x, y, z,代表城市x和城市y之間有一條耗時爲z的雙向邊。
輸出格式
對於每組數據輸出”Possible”或者”Impossible”.樣例輸入
23 3 11
0 2 7
0 1 6
1 2 5
2 1 10000
1 0 1
樣例輸出
PossibleImpossible
樣例解釋
第一組:0 -> 1 -> 2 :11第二組:顯然偶數時間都是不可能的。
數據範圍
30%: T <= 10000另有30%: n <= 5 , m <= 10.
100%: 2 <= n <= 50 , 1 <= m <= 100 , 1 <= z <= 10000 , 1 <= T <= 10^18 , Case <= 5.
題解
最近看起來做了不少神神叨叨的最短路。感覺這道題的解題思路非常的奇怪。不看正解還想不到……下面是題解的講法:
當T<= 10000的時候,可以設 vis[i][j] 代表到達第i個點時間爲j是否合法。 這樣是O(T*m),應該可以拿到小數據,就沒打了。
當T很大的時候,我們考慮如果0 -> x -> n - 1路徑時間爲T,且 從x出發有一個時間爲d的環,則 一定存在一個K滿足 K + p*d = T(至少T滿足條件),這樣我們就能繞着環走p次就能構成一條時間爲T的路徑。
顯然要求的路徑一定經過 0,而且在合法情況下從0號點出發一定存在一條邊,否則0號點和n - 1號就是不聯通的。隨便取一條邊時間爲d, 則能構成從0號點出發的一個時間爲2d的環。這樣原題就化爲最短路問題了,dis[i][j] 代表到達i號點,時間爲 j + p * 2d,最小的 j+p*2d。最後判斷dis[n -1][T % 2d] 是否小於等於T即可。實際上就是在30%的基礎上縮減狀態。時間複雜度爲O(m*d)。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define ll long long
#define MOD 1000002
using namespace std;
int C,n,m,zz,head[52],mod;
ll T,dis[52][20002];
struct bian{int to,nx,v;} e[202];
int q[10000002][2];
void insert(int x,int y,int z)
{
zz++; e[zz].to=y; e[zz].v=z; e[zz].nx=head[x]; head[x]=zz;
zz++; e[zz].to=x; e[zz].v=z; e[zz].nx=head[y]; head[y]=zz;
if(x==0||y==0) mod=2*z;
}
void init()
{
memset(head,0,sizeof(head));
zz=0; mod=-1;
scanf("%d%d%I64d",&n,&m,&T);
int i,x,y,z;
for(i=1;i<=m;i++)
{scanf("%d%d%d",&x,&y,&z);
insert(x,y,z);
}
}
void spfa()
{
int i,t=0,w=1,x,p,y,d;
memset(dis,127,sizeof(dis));
q[0][0]=0; q[0][1]=0; dis[0][0]=0;
while(t!=w)
{x=q[t][0]; y=q[t][1]; t=(t+1)%MOD;
//t++;
for(i=head[x];i;i=e[i].nx)
{p=e[i].to;
d=(e[i].v+y)%mod;
if(dis[p][d]>dis[x][y]+e[i].v)
{dis[p][d]=dis[x][y]+e[i].v;
q[w][0]=p; q[w][1]=d;
w=(w+1)%MOD;
//w++;
}
}
}
if(dis[n-1][T%mod]<=T) puts("Possible");
else puts("Impossible");
}
int main()
{
freopen("travel.in","r",stdin);
freopen("travel.out","w",stdout);
scanf("%d",&C);
while(C--)
{init();
if(mod==-1) {puts("Impossible"); continue;}
spfa();
}
return 0;
}