zoukankan      html  css  js  c++  java
  • NOIP2017 逛公园

    题目描述

    策策同学特别喜欢逛公园。公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。

    策策每天都会去逛公园,他总是从1号点进去,从NN号点出来。

    策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到NN号点的最短路长为dd,那么策策只会喜欢长度不超过d + Kd+K的路线。

    策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?

    为避免输出过大,答案对PP取模。

    如果有无穷多条合法的路线,请输出−1。

    输入输出格式

    输入格式:

    第一行包含一个整数 TT, 代表数据组数。

    接下来TT组数据,对于每组数据: 第一行包含四个整数 N,M,K,PN,M,K,P,每两个整数之间用一个空格隔开。

    接下来MM行,每行三个整数a_i,b_i,c_iai,bi,ci,代表编号为a_i,b_iai,bi的点之间有一条权值为 c_ici的有向边,每两个整数之间用一个空格隔开。

    输出格式:

    输出文件包含 TT 行,每行一个整数代表答案。

    输入输出样例

    输入样例#1: 复制
    2
    5 7 2 10
    1 2 1
    2 4 0
    4 5 2
    2 3 2
    3 4 1
    3 5 2
    1 5 3
    2 2 0 10
    1 2 0
    2 1 0
    输出样例#1: 复制
    3
    -1
    
    

    说明

    【样例解释1】

    对于第一组数据,最短路为 3。 1 – 5, 1 – 2 – 4 – 5, 1 – 2 – 3 – 5 为 3 条合法路径。

    【测试数据与约定】

    对于不同的测试点,我们约定各种参数的规模不会超过如下

    测试点编号  TT   NN   MM   KK   是否有0边
    1 5 5 10 0
    2 5 1000 2000 0
    3 5 1000 2000 50
    4 5 1000 2000 50
    5 5 1000 2000 50
    6 5 1000 2000 50
    7 5 100000 200000 0
    8 3 100000 200000 50
    9 3 100000 200000 50
    10 3 100000 200000 50

    对于 100%的数据, 1 le P le 10^9,1 le a_i,b_i le N ,0 le c_i le 10001P109,1ai,biN,0ci1000。

    数据保证:至少存在一条合法的路线。

    首先dp很好想:f[i][j]表示到i,比最短路大j的方案数

    转移可以用记忆化广搜,但效率不高

    实际上转移顺序的问题可以通过拓扑排序实现

    对于每一个j值(从小到大枚举),都可以用最短路径的拓扑序先对j进行转移

    f[Top[]][j]+=f[i][j]

    然后就可以枚举每一个点的边进行转移,因为与最短路差肯定大于j,所以不用考虑顺序:f[v][j+w+dist[u]-dist[v]]+=f[u][j]

    判断无解因为是按照最短路径拓扑,所以如果有节点未出队且通过该点的最短

    路<=(1,n)的最短路+k

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring> 
      4 #include<algorithm>
      5 #include<queue>
      6 using namespace std;
      7 struct Node
      8 {
      9      int next,to,dis;
     10 }edge[500011];
     11 int head[2][200011],dist[2][200011],n,m,k,inf=2e8;
     12 int f[200011][55],ans,Mod,num,sum,T[500011],du[200011];
     13 bool vis[200011];
     14 void add(int x,int u,int v,int dis)
     15 {
     16     num++;
     17     edge[num].next=head[x][u];
     18     head[x][u]=num;
     19     edge[num].to=v;
     20     edge[num].dis=dis;
     21 }
     22 queue<int>Q;
     23 void SPFA(int t)
     24 {int i;
     25     for (i=1;i<=n;i++)
     26     dist[t][i]=inf,vis[i]=0;
     27     while (Q.empty()==0) Q.pop();
     28     if (t==0) Q.push(1),dist[t][1]=0;
     29     else Q.push(n),dist[t][n]=0;
     30     while (Q.empty()==0)
     31     {
     32         int u=Q.front();
     33         vis[u]=0;
     34         Q.pop();
     35         for (i=head[t][u];i;i=edge[i].next)
     36         {
     37             int v=edge[i].to;
     38             if (dist[t][u]+edge[i].dis<dist[t][v])
     39             {
     40                 dist[t][v]=dist[t][u]+edge[i].dis;
     41                 if (vis[v]==0) vis[v]=1,Q.push(v); 
     42             }
     43         }
     44     }
     45 }
     46 void Top()
     47 {int i,j;
     48 while (Q.empty()==0) Q.pop();
     49 for (i=0;i<=n;i++)du[i]=0;
     50     for (i=1;i<=n;i++)
     51     {
     52         for (j=head[0][i];j;j=edge[j].next)
     53         if (dist[0][i]+edge[j].dis==dist[0][edge[j].to]) du[edge[j].to]++;
     54     }
     55     for (i=1;i<=n;i++)
     56     if (du[i]==0) Q.push(i),sum++,T[sum]=i;
     57     while (Q.empty()==0)
     58     {
     59         int u=Q.front();
     60         Q.pop();
     61         for (i=head[0][u];i;i=edge[i].next)
     62         {
     63             int v=edge[i].to;
     64             if (dist[0][v]==dist[0][u]+edge[i].dis)
     65             {
     66                 du[v]--;
     67                 if (du[v]==0) Q.push(v),sum++,T[sum]=v;
     68             }
     69         }
     70     }
     71 }
     72 void DP()
     73 {int i,j,l;
     74     f[1][0]=1;
     75     for (i=0;i<=k;i++)
     76     {
     77         for (j=1;j<=sum;j++)
     78         {
     79             int u=T[j];
     80             if (f[u][i]==0) continue;
     81             for (l=head[0][u];l;l=edge[l].next)
     82             {
     83                 int v=edge[l].to;
     84                 if (dist[0][v]==dist[0][u]+edge[l].dis)
     85                 f[v][i]=(f[v][i]+f[u][i])%Mod;
     86             }
     87         }
     88         for (j=1;j<=n;j++)
     89         if (f[j][i])
     90         for (l=head[0][j];l;l=edge[l].next)
     91         {
     92             int v=edge[l].to;
     93             if (dist[0][v]!=dist[0][j]+edge[l].dis)
     94             if (dist[0][j]+edge[l].dis-dist[0][v]+i<=k)
     95             {
     96                 f[v][dist[0][j]+edge[l].dis-dist[0][v]+i]=(f[v][dist[0][j]+edge[l].dis-dist[0][v]+i]+f[j][i])%Mod;
     97             }
     98         }
     99     }
    100     ans=0;
    101     for (i=0;i<=k;i++)
    102     ans=(ans+f[n][i])%Mod;
    103     printf("%d
    ",ans);
    104 }
    105 int main()
    106 {int T,i,j,u,v,d,flag;
    107  cin>>T;
    108      while (T--)
    109      {
    110          cin>>n>>m>>k>>Mod;
    111          num=0;
    112          sum=0;
    113          for (i=0;i<=200000;i++)
    114          head[0][i]=head[1][i]=0;
    115          for (i=0;i<=n;i++)
    116          for (j=0;j<=k;j++)
    117          f[i][j]=0;
    118         for (i=1;i<=m;i++)
    119         {
    120             scanf("%d%d%d",&u,&v,&d);
    121             add(0,u,v,d);add(1,v,u,d);
    122         } 
    123         SPFA(0);SPFA(1);
    124         Top();
    125         flag=0;
    126         for (i=1;i<=n;i++)
    127         if (du[i]&&dist[0][i]+dist[1][i]<=dist[0][n]+k)
    128         {
    129             printf("-1
    ");
    130             flag=1;
    131             break;
    132         }
    133         if (flag==0)
    134             DP();
    135      }
    136 } 
  • 相关阅读:
    小白扫盲之-计算机为何需要内存
    Centos 安装Pycharm 并移动到桌面。
    Docker守护进程
    插入排序
    快速排序
    归并排序
    __metaclass__方法
    Python面向对象(2)类空间问题以及类之间的关系
    Python面向对象(1)_初步认识
    python语法基础(8)_包
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8022740.html
Copyright © 2011-2022 走看看