zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    C语言中返回字符串函数的四种实现方法
    (转)大整数除法jva.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result异常的解决方法
    @Transactional使用try->catch捕获异常并回滚方法
    Golang1.13.x 解决go get 无法下载问题
    Zookeeper:Unable to read additional data from client sessionid 0x00, likely client has closed socket
    解决Linux系统下面javamelody图片中文乱码问题
    mybatis查询mysql的datetime类型数据时间差了14小时
    以太坊多重钱包离线签名
    Solidity智能合约如何判断地址为0或空
    Solidity开发注意
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9893288.html
Copyright © 2011-2022 走看看