NOIP 2017 逛公园 - 动态规划 - 最短路
跑一遍最短路。
一个点拆$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 }