• LOJ2316. 「NOIP2017」逛公园【DP】【最短路】【思维】


    LINK

    思路

    因为我想到的根本不是网上的普遍做法

    所以常数出奇的大,而且做法极其暴力

    可以形容是带优化的大模拟

    进入正题:

    首先一个很显然的思路是如果在合法的路径网络里面存在零环是有无数组解的

    然后这个直接对所有边权是0的边进行一次toposort看看有没有点没有被访问到

    然后剩下的dp怎么设计?

    (dp_{i,j})表示走到了第i个点,如果当前点到n走最短路最后路径比最短路径多出来了j

    然后转移的时候发现是需要搞定顺序的问题?咋办?

    发现一条边新的贡献是(dis2_{v}+E[i].w-dis2_u),其中dis2是反图跑出来的最短路

    然后就可以把每条边的权值换一下

    发现这个时候我们要先枚举j进行转移

    这样就把状态转移分成了若干个层次

    然后发现新的边权如果是0的话会在同一层之间转移

    并且可以保证新的边权是没有0环的

    那就再做一遍toposort就好了

    随便跑一跑多好的

    然后同一层你就先跑所有新的权值是0的边,同层转移完了之后你再跑权值不是0的边转移到下一层就可以了


    附带Debug全套餐。。。良心对拍程序(懒得删了)


    //Author: dream_maker
    #include<bits/stdc++.h>
    using namespace std;
    //----------------------------------------------
    //typename
    typedef long long ll;
    //convenient for
    #define fu(a, b, c) for (int a = b; a <= c; ++a)
    #define fd(a, b, c) for (int a = b; a >= c; --a)
    #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
    //inf of different typename
    const int INF_of_int = 1e9;
    const ll INF_of_ll = 1e18;
    //fast read and write
    template <typename T>
    void Read(T &x) {
      bool w = 1;x = 0;
      char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = 0, c = getchar();
      while (isdigit(c)) {
        x = (x<<1) + (x<<3) + c -'0';
        c = getchar();
      }
      if (!w) x = -x;
    }
    template <typename T>
    void Write(T x) {
      if (x < 0) {
        putchar('-');
        x = -x; 
      }
      if (x > 9) Write(x / 10);
      putchar(x % 10 + '0');
    }
    //----------------------------------------------
    //#define Debug 
    typedef pair<int, int> pi;
    const int N = 2e5 + 10;
    const int M = 55;
    struct Edge {
      int u, v, w, nxt;
      bool dir, eras;
    } E[N << 1];
    int head[N], tot = 0, vis[N];
    int dis1[N], dis2[N], deg[N], topoid[N];
    int n, m, k, p, minidis, dp[N][M];
    void init() {
      tot = 0;
      fu(i, 1, n) head[i] = deg[i] = 0;
      fu(i, 1, n)
        fu(j, 0, k) dp[i][j] = 0;
    }
    void addedge(int u, int v, int w) {
    #ifdef Debug
      printf("EDGE:[%d, %d]: %d
    ", u, v, w);
    #endif
      E[++tot] = (Edge) {u, v, w, head[u], 0, 0}, head[u] = tot;
      E[++tot] = (Edge) {v, u, w, head[v], 1, 0}, head[v] = tot;
    }
    void add(int &a, int b) {
      if ((a += b) >= p) a -= p;
    }
    void Dijkstra1() {
      static priority_queue<pi, vector<pi>, greater<pi> > q; 
      fu(i, 1, n) dis1[i] = INF_of_int, vis[i] = 0;
      dis1[1] = 0;
      q.push(pi(dis1[1], 1));
      while (q.size()) {
        int u = q.top().second; q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = head[u]; i; i = E[i].nxt) {
          int v = E[i].v;
          if (!E[i].dir && dis1[v] > dis1[u] + E[i].w) {
            dis1[v] = dis1[u] + E[i].w;
            q.push(pi(dis1[v], v));
          }
        }
      }
    }
    void Dijkstra2() {
      static priority_queue<pi, vector<pi>, greater<pi> > q; 
      fu(i, 1, n) dis2[i] = INF_of_int, vis[i] = 0;
      dis2[n] = 0;
      q.push(pi(dis2[n], n));
      while (q.size()) {
        int u = q.top().second; q.pop();
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = head[u]; i; i = E[i].nxt) {
          int v = E[i].v;
          if (E[i].dir && dis2[v] > dis2[u] + E[i].w) {
            dis2[v] = dis2[u] + E[i].w;
            q.push(pi(dis2[v], v));
          }
        }
      }
    }
    bool toposort() {
      int ind = 0;
      fu(i, 1, n) vis[i] = 0;
      fu(i, 1, tot) {
        if (E[i].eras || E[i].w) continue;
        deg[E[i].v]++;
      }
      static queue<int> topo;
      fu(i, 1, n) if (!deg[i]) topo.push(i);
      while (topo.size()) { 
        int u = topo.front(); topo.pop();
    #ifdef Debug
        printf("Topotost :: Reach: %d
    ", u);
    #endif
        topoid[++ind] = u, vis[u] = 1;
        for (int i = head[u]; i; i = E[i].nxt) {
          int v = E[i].v;
          if (E[i].w || E[i].eras) continue;
          if (--deg[v] == 0) topo.push(v);
        }
      }
      fu(i, 1, n) if (deg[i]) return 1;
      fu(i, 1, n) if (!vis[i]) topoid[++ind] = i;
      return 0;
    }
    void DP() {
      dp[1][0] = 1;
      fu(j, 0, k) {
    #ifdef Debug
        printf("In the case :: %d
    ", j);
    #endif
        fu(id, 1, n) if (dp[topoid[id]][j]) {
          int u = topoid[id];
          for (int i = head[u]; i; i = E[i].nxt) {
            if (E[i].eras || E[i].w) continue;
            int v = E[i].v;
            add(dp[v][j], dp[u][j]);
    #ifdef Debug
            printf("Trans between:[%d, %d] :: old value : %d new value : %d
    ", u, v, j, E[i].w);
    #endif
          }
        }
        fu(id, 1, n) if (dp[topoid[id]][j]) {
          int u = topoid[id];
          for (int i = head[u]; i; i = E[i].nxt) {
            if (E[i].eras || !E[i].w) continue;
            int v = E[i].v;
            if (j + E[i].w > k) continue;
            add(dp[v][j + E[i].w], dp[u][j]);
    #ifdef Debug
            printf("Trans between:[%d, %d] :: old value : %d new value : %d
    ", u, v, j, E[i].w);
    #endif
          }
        }
      }
    }
    void solve() {
      Read(n), Read(m), Read(k), Read(p);
      init();
      fu(i, 1, m) {
        int u, v, w;
        Read(u), Read(v), Read(w);
        addedge(u, v, w);
      }
      Dijkstra1();
      Dijkstra2();
    #ifdef Debug
      fu(i, 1, n) cout<<dis1[i]<<" "<<dis2[i]<<endl;
    #endif
      minidis = dis1[n];
      if (dis1[n] >= INF_of_int) {
        printf("0
    ");
        return;
      }
      fu(i, 1, tot) {
        if (!E[i].dir) {
          if (dis1[E[i].u] + E[i].w + dis2[E[i].v] > minidis + k) E[i].eras = 1;
        } else E[i].eras = 1;
      }
      if (toposort()) {
        printf("-1
    ");
        return;
      }
      fu(i, 1, tot) {
        if (E[i].eras) continue;
        E[i].w = dis2[E[i].v] - dis2[E[i].u] + E[i].w;
      }
      toposort();
    #ifdef Debug
      fu(i, 1, n) printf("%d ", topoid[i]);
      putchar('
    ');
    #endif
      DP();
      int ans = 0;
      fu(i, 0, k) add(ans, dp[n][i]);
      Write(ans), putchar('
    ');
    }
    int main() {
    #ifdef dream_maker
      freopen("input.txt", "r", stdin);
    #endif
      int T; Read(T);
      while (T--) solve(); 
      return 0;
    }
    
  • 相关阅读:
    SpringCloud与SpringBoot区别
    Spring cloud概念
    微服务框架对比
    期末作品检查
    管理信息系统 第三部分 作业
    作业38——模型分离(选做)
    作业37——密码保护
    作业36——实现搜索功能
    作业35——完成个人中心—导航标签
    作业34——个人中心标签页导航
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9893288.html
Copyright © 2020-2023  润新知