zoukankan      html  css  js  c++  java
  • [NOIp 2017]逛公园

    Description

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

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

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

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

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

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

    Input

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

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

    接下来$M$行,每行三个整数$a_i,b_i,c_i$,代表编号为$a_i,b_i$的点之间有一条权值为 $c_i$的有向边,每两个整数之间用一个空格隔开。

    Output

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

    Sample Input

    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

    Sample Output

    3
    -1

    Hint

    【样例解释1】

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

    【测试数据与约定】

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

    测试点编号  $T$   $N$   $M$   $K$   是否有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 1000$。

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

    题解(转载)

    ->原文地址<-

    • 这题如果直接$DP$的话,会发现有后效性,则会重复统计答案。
    • 但看到 $k≤50$ ,很小,于是我们考虑拆点。
    • 先做一次 $SPFA$,设 $1$ 到 $i$ 号点的最短路为 $dist1[i]$ 。
    • 之后把每个点拆成 $k+1$ 个点,分别对应到这个点时的路径长 $j-dist1[i]$ 的值。
    • 由于这个值的范围只在 $[0,k]$ 之间,
    • 那么我们对于开始时的有向边的两个点拆点,并进行进行连接。
    • 这样我们就构成了一个拓扑图,跑一遍拓扑排序即可。
    • 当跑完后发现并没有遍历所有点,则直接输出 $-1$ 即可。
    • 而且这题还要卡卡常,发现连边时连接了很多无用点,拖慢了拓扑排序的速度。
    • 于是我们考虑倒着做一遍 $SPFA$ (从 $n$ 开始),设 $n$ 到 $i$ 号点的最短路为 $dist2[i]$ 。
    • 当一个点 $dist1[u[i]]+dist2[v[i]]>dist1[n]+k$ 时,说明这个点就没用了,不需要从它连边出去。
    • 时间复杂度 $O(T*M*K)$ 。
      1 //Is is made by Awson on 2017.12.16
      2 #include <set>
      3 #include <map>
      4 #include <cmath>
      5 #include <ctime>
      6 #include <queue>
      7 #include <stack>
      8 #include <cstdio>
      9 #include <string>
     10 #include <vector>
     11 #include <cstdlib>
     12 #include <cstring>
     13 #include <iostream>
     14 #include <algorithm>
     15 #define LL long long
     16 #define Max(a, b) ((a) > (b) ? (a) : (b))
     17 #define Min(a, b) ((a) < (b) ? (a) : (b))
     18 #define getnode(x, y) (((x)-1)*(k+1)+(y))
     19 using namespace std;
     20 const int N = 100000;
     21 const int M = 200000;
     22 const int K = 50;
     23 int read() {
     24     int sum = 0;
     25     char ch = getchar();
     26     while (ch < '0' || ch > '9') ch = getchar();
     27     while (ch >= '0' && ch <= '9') sum = (sum<<1)+(sum<<3)+ch-'0', ch = getchar();
     28     return sum;
     29 }
     30 
     31 int n, m, p, k, u[M+5], v[M+5], c[M+5];
     32 struct tt {
     33     int to, next, cost;
     34 }edge[(M*K<<1)+5];
     35 int path[(N*K<<1)+5], top, path2[N+5];
     36 int dist[N+5][2];
     37 bool vis[N+5];
     38 int Q[(N*K<<1)+5], head, tail;
     39 int ans[(N*K<<1)+5], in[(N*K<<1)+5];
     40 void add(int u, int v, int c) {
     41     edge[++top].to = v;
     42     edge[top].cost = c;
     43     edge[top].next = path[u];
     44     path[u] = top;
     45 }
     46 void add2(int u, int v, int c) {
     47     edge[++top].to = v;
     48     edge[top].cost = c;
     49     edge[top].next = path2[u];
     50     path2[u] = top;
     51 }
     52 void SPFA(int u, int t) {
     53     dist[u][t] = 0;
     54     memset(vis, 0, sizeof(vis)); vis[u] = 1;
     55     Q[head = tail = 0] = u; tail++;
     56     while (head < tail) {
     57         int u = Q[head]; ++head, vis[u] = 0;
     58         for (int i = path2[u]; i; i = edge[i].next)
     59             if (dist[edge[i].to][t] > dist[u][t]+edge[i].cost) {
     60                 dist[edge[i].to][t] = dist[u][t]+edge[i].cost;
     61                 if (!vis[edge[i].to]) {
     62                     vis[edge[i].to] = 1; Q[tail] = edge[i].to, ++tail;
     63                 }
     64             }
     65     }
     66 }
     67 void topsort() {
     68     memset(ans, 0, sizeof(ans)); ans[0] = 1;
     69     int MAX = getnode(n, k), sum = 0; head = tail = 0;
     70     for (int i = 0; i <= MAX; ++i) if (!in[i]) Q[tail] = i, ++tail;
     71     while (head < tail) {
     72         int u = Q[head]; ++head, ++sum;
     73         for (int i = path[u]; i; i = edge[i].next) {
     74             --in[edge[i].to]; ans[edge[i].to] = (ans[edge[i].to]+ans[u])%p;
     75             if (!in[edge[i].to]) Q[tail] = edge[i].to, ++tail;
     76         }
     77     }
     78     if (MAX+1 != sum) {
     79         printf("-1
    "); return;
     80     }
     81     int cnt = 0;
     82     for (int i = 0; i <= k; i++)
     83         cnt = (cnt+ans[getnode(n, i)])%p;
     84     printf("%d
    ", cnt);
     85 }
     86 
     87 void work() {
     88     n = read(), m = read(), k = read(), p = read();
     89     memset(dist, 127/3, sizeof(dist));
     90     memset(path2, top = 0, sizeof(path2));
     91     for (int i = 1; i <= m; i++) {
     92         u[i] = read(), v[i] = read(), c[i] = read();
     93         add2(u[i], v[i], c[i]);
     94     }
     95     SPFA(1, 0);
     96     memset(path2, top = 0, sizeof(path2));
     97     for (int i = 1; i <= m; i++) add2(v[i], u[i], c[i]);
     98     SPFA(n, 1);
     99     memset(path, top = 0, sizeof(path));
    100     memset(in, 0, sizeof(in));
    101     for (int i = 1; i <= m; i++) {
    102         int a = u[i], b = v[i], d = c[i];
    103         if (d <= dist[b][0]-dist[a][0]+k) {
    104             int delta = d-(dist[b][0]-dist[a][0]), basea = getnode(a, 0), baseb = getnode(b, delta);
    105             for (int j = 0; j <= k-delta && dist[a][0]+dist[b][1]+d+j <= dist[n][0]+k; j++) {
    106                 add(basea+j, baseb+j, 0);
    107                 in[baseb+j]++;
    108             }
    109         }
    110     }
    111     topsort();
    112 }
    113 int main() {
    114     int t; cin >> t;
    115     while (t--) work();
    116     return 0;
    117 }
  • 相关阅读:
    雷林鹏分享:XML to HTML
    雷林鹏分享:XML DOM
    雷林鹏分享:XML 编码
    雷林鹏分享: XML CDATA
    雷林鹏分享:服务器上的 XML
    雷林鹏分享:XML 注意事项
    雷林鹏分享:现实生活中的 XML
    雷林鹏分享:XML 相关技术
    雷林鹏分享:XML
    Android 系统架构图
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8048089.html
Copyright © 2011-2022 走看看