题目大意:有一张$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;
}