开车旅行 travel

题目描述

J Y 是一个爱旅游的探险家,也是一名强迫症患者。现在 J Y 想要在 C 国进行一次长途旅行,C国拥有n个城市(编号为 0 , 1 , 2... , n 1 ),城市之间有 m 条道路,可能某个城市到自己有一条道路,也有可能两个城市之间有多条道路,通过每条道路都要花费一些时间。 J Y 从0号城市开始出发,目的地为 n 1 号城市。由于 J Y 想要好好参观一下C国,所以 J Y 想要旅行恰好 T 小时。为了让自己的旅行更有意思, J Y 决定不在任何一个时刻停留(走一条到城市自己的路并不算停留)。 J Y 想知道是否能够花恰好T小时到达 n 1 号城市(每个城市可经过多次)。现在这个问题交给了你。
若可以恰好到达输出“ P o s s i b l e ”否则输出“ I m p o s s i b l e ”。(不含引号)。

输入格式

第一行一个正整数 C a s e ,表示数据组数。
每组数据第一行 3 个整数,分别为 n , m , T
接下来 m 行,每行 3 个整数 x , y , z ,代表城市 x 和城市 y 之间有一条耗时为 z 的双向边。

输出格式

对于每组数据输出” P o s s i b l e ”或者” I m p o s s i b l e ”.

数据范围

30%: T 10000
另有
30%: n 5 , m 10.
100%: 2 n 50 , 1 m 100 , 1 z 10000 , 1 T 10 18 , C a s e 5.

Solutiuon

前言

之所以拿出这道题,因为这是一道非常好的模板题。

30opt

30 o p t 算是容易想到。用 d i s [ i ] [ j ] 表示到达 i 位置用了 j 时间。实际上就是对一个点分成很多不同的状态,然后把一个状态看成一个点加入队列用SPFA的思想 d p 看是否能到达就可以了。

100opt

注意到 T 值巨大,不得不优化一下算法。我们发现对于 d i s [ i ] [ j ] 来说,到达 i 的时间一定是j.显然有大部分状态没有用。我们发现如果到达i时有这样两个时间 j j + k ,这两种时间显然都是合法的,也就是有一种走法可以实现的 ,那么如果这个k值有特殊意义的话,那么此题很好办。如果这个 k 值可以在任何一种走法中加入若干次,那么如果到达一个点存在一种走法使得到这点的时间为 j ,那么一定有走法使得到这点时间为 j + k , j + 2 k , j + 3 k , j + 4 k , . . . . . . ,因为 k 可以任意加入,那么,这样的 k 是什么?
k一定可以是从起点出发的,然后回到起点的一个环的长度。这样的合法性显然。
清楚了这个,如果 d i s [ i ] [ j ] 合法,那么 d i s [ i ] [ j + n × k ] , n N 合法。
那么这些就没有必要存储了。进而推知,只需存储 d i s [ i ] [ j mod k ] 的状态。这样相当于把之前所有的 j 都转化成了 j mod k 。那么这样的转移会有错误吗?实际上由于取模运算具有较强的灵活性, ( j 1 + n × k + j 2 + p × k ) 整体取模 k ( j 1 + j 2 ) 取模k是一样的,所以转移式

d p [ i ] [ ( l e n + w ) mod k ] = d p [ p ] [ l e n ] + w

仔细研究转移式, d p [ i ] [ j ] 的值一定可以写成 j + k × n 的形式,所以 d p [ i ] [ j ] 的值越小越优,越能证明他能达到比他大 n × k 的时间.所以此处需套用最短路的模板.
接下来,判断一下能否在终点到达 T 时刻.我们知道如果能够,那么一定 d p [ n ] [ T mod k ] 有值,这个值又可以写成 ( T mod k ) + k × p 1 , p 1 N , T 也可以写成 ( T mod k ) + k × p 2 , p 2 N ,如果这个值小于T,也就是 p 1 p 2 那么一定可以在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;
    }

猜你喜欢

转载自blog.csdn.net/jh_2002/article/details/80638683