[洛谷P4822][BJWC2012]冻结
题目大意:有一张$n(n\leqslant50)$个点$m(m\leqslant1000)$条边的无向图,可以使得$k$条边使得边权减半,求最短路
题解:分层图最短路
卡点:无
C++ Code:
#include <cstdio> #include <cstring> #define maxn 52 #define maxm 1010 #define maxk 51 #define N (maxn * maxk) #define M (maxm * maxk * 2) int head[N], cnt; struct Edge { int to, nxt, w; } e[M << 1]; inline void addedge(int a, int b, int c) { e[++cnt] = (Edge) {b, head[a], c}; head[a] = cnt; } inline void addedge2(int a, int b, int c) { addedge(a, b, c); addedge(b, a, c); } int n, m, k, nn; const int inf = 0x3f3f3f3f; int dis[N]; inline int getmin(int a, int b) { return dis[a] < dis[b] ? a : b; } namespace SgT { int V[N << 2]; void modify(int rt, int l, int r, int pos, int num) { if (l == r) { V[rt] = num; return ; } const int mid = l + r >> 1; if (pos <= mid) modify(rt << 1, l, mid, pos, num); else modify(rt << 1 | 1, mid + 1, r, pos, num); V[rt] = getmin(V[rt << 1], V[rt << 1 | 1]); } } int dijkstra(int S, int T) { memset(dis, 0x3f, sizeof dis); dis[S] = 0; SgT::modify(1, 1, nn, S, S); for (int Tim = nn; Tim; --Tim) { int u = SgT::V[1]; SgT::modify(1, 1, nn, u, 0); for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (dis[v] > dis[u] + e[i].w) { dis[v] = dis[u] + e[i].w; SgT::modify(1, 1, nn, v, v); } } } return dis[T]; } int main() { scanf("%d%d%d", &n, &m, &k); nn = n * k + n; for (int i = 0, a, b, c; i < m; ++i) { scanf("%d%d%d", &a, &b, &c); for (int j = 0; j <= k; ++j) { addedge2(j * n + a, j * n + b, c); if (j) { addedge((j - 1) * n + a, j * n + b, c >> 1); addedge((j - 1) * n + b, j * n + a, c >> 1); } } } for (int i = 0; i < k; i++) addedge(i * n + n, (i + 1) * n + n, 0); printf("%d\n", dijkstra(1, k * n + n)); return 0; }