[洛谷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;
}

  

猜你喜欢

转载自www.cnblogs.com/Memory-of-winter/p/10225242.html