zoukankan      html  css  js  c++  java
  • 51nod 1326 奇妙的spfa+dp

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1326

    1326 遥远的旅途

    题目来源: TopCoder
    基准时间限制:2 秒 空间限制:131072 KB 分值: 320 难度:7级算法题
    收藏
    关注
    一个国家有N个城市,这些城市被标为0,1,2,...N-1。这些城市间连有M条道路,每条道路连接两个不同的城市,且道路都是双向的。一个小鹿喜欢在城市间沿着道路自由的穿梭,初始时小鹿在城市0处,它最终的目的地是城市N-1处。小鹿每在一个城市,它会选择一条道路,并沿着这条路一直走到另一个城市,然后再重复上述过程。每条道路会花费小鹿不同的时间走完,在城市中小鹿不花时间逗留。路程中,小鹿可以经过一条路多次也可以经过一个城市多次。给定城市间道路的信息,问小鹿是否有一种走法,从城市0出发到达城市N-1时,恰好一共花费T个单位的时间。如果存在输出“Possible”,否则输出“Impossible”。
    注意,小鹿在整个过程中可以多次经过城市N-1,只要最终小鹿停在城市N-1即可。
     
    例如样例中小鹿的行程可以是0->1->2->0->2.
    Input
    多组测试数据,输入的第一行含一个整数caseT,表示测试数据个数,1<=caseT<=3.
    之后有caseT组相同结构的测试数据,每组测试数据构成如下:
    第一行三个整数,N,M,T,且2<=N<=50,1<=M<=50,1<=T<=1,000,000,000,000,000,000(即
    10^18).
    之后M行,每行三个整数Ai,Bi,Di,表示城市Ai与Bi间有一条双向道路,且小鹿穿越这条路要花费Di的时间。其中,0<=Ai,Bi<N,1<=Di<=10000。
    Output
    每组测试数据一行输出,如果存在题目所述路径输出“Possible”,否则“Impossible”,不含引号。
    Input示例
    1
    3 3 25
    0 2 7
    0 1 6
    1 2 5
    Output示例
    Possible
     T很大,如果直接bfs暴力的话肯定是不行的。
    题解看得也很玄学感觉还是有点不明白这样做的可行性,就是对于T很大的情况肯定要走环才能抵消这么大的路程,
    我们不妨以N为结束点,N的入边作为环来延长总路径,假设有一条连接N点的边权值为w,有一条长度为k从1-N的路径,
    如果(T-k)%(2*w)==0&&k<=T,我们就可以认定这是有可能的,我一直想要是这个环不在末尾而是处于中间会不会出现很多节点导致T,不过并没有出现,具体的证明我也不会。只能先码上了。
    dis[i][j]表示(1->i点的距离%mod)=j的最小距离,mod=2*w,直接跑spfa更新就好了,如果dis[N][T%(2*w)]<=T,说明可能,否则不可能。
    用dp表示的话似乎好理解了那么一点,因为边权最大1w,所有的路径长度模完之后最多也就两万种情况。

    基本思想:能否在T时刻刚好到达n号点,可选n点的任一入边(q-->n),记录边长ds,看能否在S时刻到达q,且   (T-S)%(2*ds)==0(S<=T)

    然后可以设dp[x][y] 表示到达x点,并且使dp[i][j]%(2*ds)==j 成立的最小时刻。初始化dp[1][0]=0;然后跑SPFADP方程dp[k][ (j+dis[i][k])%(2*ds) ] = min { dp[i][j] + dis[i][k] }

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define inf 0x3f3f3f3f
     4 struct Edge{int to,w,next;}e[115];
     5 int cnt,first[55];
     6 long long d[55][20005];
     7 void add(int u,int v,int w)
     8 {
     9     e[cnt].w=w;
    10     e[cnt].to=v;
    11     e[cnt].next=first[u];
    12     first[u]=cnt++;
    13 }
    14 struct node{int u,w;};
    15 
    16 bool vis[55][20005];
    17 long long spfa(int N,int  mod,long long  T)
    18 {
    19    memset(vis,0,sizeof(vis));
    20    memset(d,inf,sizeof(d));
    21    queue<node>Q;
    22    Q.push(node{1,0});
    23    vis[1][0]=1;
    24    d[1][0]=0;
    25    while(!Q.empty()){
    26     node t1=Q.front(); Q.pop();
    27     vis[t1.u][t1.w]=0;
    28     for(int i=first[t1.u];i+1;i=e[i].next){
    29         Edge x=e[i];
    30         if(d[x.to][(t1.w+x.w)%mod]>d[t1.u][t1.w]+x.w){
    31             d[x.to][(t1.w+x.w)%mod]=d[t1.u][t1.w]+x.w;
    32             if(!vis[x.to][(t1.w+x.w)%mod]){
    33                 Q.push(node{x.to,(t1.w+x.w)%mod});
    34                 vis[x.to][(t1.w+x.w)%mod]=1;
    35             }
    36         }
    37     }
    38    }
    39    return d[N][T%mod];
    40 }
    41 int main()
    42 {
    43     int C,N,M,i,j,k;
    44     long long T;
    45     while(cin>>C){
    46         while(C--){
    47             int a,b,c;
    48             cin>>N>>M>>T;
    49             cnt=0;
    50             memset(first,-1,sizeof(first));
    51         while(M--){
    52             cin>>a>>b>>c;
    53             a++;b++;
    54             add(a,b,c);
    55             add(b,a,c);
    56         }
    57         bool ok=0;
    58         for(i=0;i<cnt;i+=2)
    59         {
    60             if(e[i].to==N||e[i+1].to==N)
    61             {
    62               int w=2*e[i].w;
    63               if(spfa(N,w,T)<=T){ok=1;break;}
    64             }
    65         }
    66         ok?puts("Possible"):puts("Impossible");
    67     }
    68     }
    69     //system("pause");
    70     return 0;
    71 }
  • 相关阅读:
    android 开机启动
    android 获取lanucher 列表
    原创高端影楼人像专业磨皮法教程详解 附PSD源码
    [转]在SQLPLUS启动和停止Oracle数据库
    挑印刷时间最新的地图!
    Eclipse3.2下进行ArcGIS Server 9.2 Java WebADF开发手记 Eclipse使用技巧
    [藏]常用的匹配正则表达式和实例
    [藏]C# 中的常用正则表达式总结
    [转]使用uDig制作geoserver中需要的style
    [转]geoserver与OpenLayers配置入门
  • 原文地址:https://www.cnblogs.com/zzqc/p/7367576.html
Copyright © 2011-2022 走看看