NOIP 2017 逛公园 - 动态规划 - 最短路

题目传送门

  传送门

题目大意

  给定一个$n$个点$m$条边的带权有向图,问从$1$到$n$的距离不超过最短路长度$K$的路径数。

  跑一遍最短路。

  一个点拆$K + 1$个点,变成一个DAG上路径计数问题。直接拓扑排序加动态规划,如果有一个$n$号点的剩余度数非0,就一个合法的路径上存在零环(这样可以无线走了)。

  于是成功T掉了。

  把拓扑排序变成不建图,从$n$开始记忆化搜索,然后就过了。

  我居然把模数P打错成M调了一个上午,果然我菜啊。。。

  下面这份代码获得了 97 分的好成绩,我也不知道发生了什么。

Code

  1 /**
  2  * Uoj
  3  * Problem#331
  4  * Accepted
  5  * Time: 2392ms
  6  * Memory: 28196k
  7  */
  8 #include <iostream>
  9 #include <cassert>
 10 #include <cstdlib>
 11 #include <cstdio>
 12 #include <vector>
 13 #include <queue>
 14 using namespace std;
 15 typedef bool boolean;
 16 
 17 typedef pair<int, int> pii;
 18 
 19 const int N = 1e5 + 5, M = 2e5 + 5, Kmx = 52;
 20 
 21 const signed int inf = (signed) (~0u >> 1);
 22 
 23 template <typename T>
 24 void pfill(T* pst, const T* ped, T val) {
 25     for ( ; pst != ped; *(pst++) = val);
 26 }
 27 
 28 typedef class Edge {
 29     public:
 30         int ed, nx, w;
 31 
 32         Edge(int ed = 0, int nx = 0, int w = 0):ed(ed), nx(nx), w(w) {    }
 33 }Edge;
 34 
 35 typedef class MapManager {
 36     public:
 37         int *h;
 38         vector<Edge> es;
 39 
 40         MapManager(int n) {
 41             h = new int[(n + 1)];
 42         }
 43 
 44         void init(int n) {
 45             pfill(h + 1, h + n + 1, -1);
 46             es.clear();
 47         }    
 48 
 49         void addEdge(int u, int v, int w) {
 50             es.push_back(Edge(v, h[u], w));
 51             h[u] = (signed) es.size() - 1;        
 52         }
 53 
 54         Edge& operator [] (int p) {
 55             return es[p];
 56         }
 57 }MapManager;
 58 
 59 typedef class Node {
 60     public:
 61         int p, dis;
 62 
 63         Node(int p = 0, int dis = 0):p(p), dis(dis) {    }
 64 
 65         boolean operator < (Node b) const {
 66             return dis > b.dis;
 67         }
 68 }Node;
 69 
 70 int n, m, K, P;
 71 MapManager g(N), _g(N);
 72 
 73 int add(int a, int b) {
 74     return ((a += b) >= P) ? (a - P) : (a);
 75 }
 76 
 77 inline void init() {
 78     scanf("%d%d%d%d", &n, &m, &K, &P);
 79     g.init(n + 1), _g.init(n + 1);
 80     for (int i = 1, u, v, w; i <= m; i++) {
 81         scanf("%d%d%d", &u, &v, &w);
 82         g.addEdge(u, v, w);
 83         _g.addEdge(v, u, w);
 84     }
 85 }
 86 
 87 int f[N];
 88 priority_queue<Node> que;
 89 
 90 int& operator * (Node p) {
 91     return f[p.p];
 92 }
 93 
 94 void dijstra() {
 95     pfill(f + 1, f + n + 1, inf);
 96     que.push(Node(1, f[1] = 0));
 97     while (!que.empty()) {
 98         Node e = que.top();
 99         que.pop();
100         if (*e != e.dis)
101             continue;
102         for (int i = g.h[e.p]; ~i; i = g[i].nx)
103             if (*e + g[i].w < f[g[i].ed])
104                 que.push(Node(g[i].ed, f[g[i].ed] = *e + g[i].w));
105     }
106 }
107 
108 int h[N][Kmx];
109 unsigned char vis[N][Kmx];
110 boolean cir = false;
111 int dp(int p, int dif) {
112     if (dif > K)
113         return 0;
114     if (dif < 0)
115         return 0;
116     assert(dif >= 0);
117     if (vis[p][dif] & 2)
118         return cir = true;
119     if (vis[p][dif] & 1)
120         return h[p][dif];
121     vis[p][dif] |= 3, h[p][dif] = (p == 1 && dif == 0);
122     for (int i = _g.h[p], e, nd; ~i; i = _g[i].nx) {
123         e = _g[i].ed;
124         if (f[e] == inf)
125             continue;
126         nd = f[p] + dif - _g[i].w - f[e];
127         h[p][dif] = add(h[p][dif], dp(e, nd));
128         if (cir)
129             return 0;
130     }
131     vis[p][dif] ^= 2;
132     return h[p][dif];
133 }
134 
135 inline void solve() {
136     dijstra();
137     if (f[n] == inf) {
138         puts("0");
139         return;
140     }
141     cir = false;
142     pfill(vis[1], vis[n + 1], (unsigned char)0);
143     int rt = dp(n, 0);
144     for (int i = 1; i <= K && !cir; i++)
145         rt = add(rt, dp(n, i));
146     printf("%d\n", (cir) ? (-1) : (rt));
147 }
148 
149 int T;
150 int main() {
151     scanf("%d", &T);
152     while (T--) {
153         init();
154         solve();
155     }
156     return 0;
157 }
posted @ 2018-11-05 12:55  阿波罗2003  阅读(...)  评论(... 编辑 收藏