「LibreOJ #10064」 黑暗城堡

知道黑暗城堡有 \(N\) 个房间,\(M\) 条可以制造的双向通道,以及每条通道的长度。
城堡是树形的并且满足下面的条件:
\(D_i\) 为如果所有的通道都被修建,第 \(i\) 号房间与第 \(1\) 号房间的最短路径长度;
\(S_i\) 为实际修建的树形城堡中第 \(i\) 号房间与第 \(1\) 号房间的路径长度;
要求对于所有整数 \(i(1≤i≤N)\),有 \(S_i=D_i\) 成立。
你想知道有多少种不同的城堡修建方案。当然,你只需要输出答案对 \(2^{31}−1\) 取模之后的结果就行了。

Loj

分析

第一步肯定求出 \(1\) 号节点到每个点的最短路,然后考虑建路。

因为要保证建好的路必须使该节点到 \(1\) 号节点的实际路径长度等于最短路长度,所以我们枚举每个点 \(u\) ,与 \(u\) 相连的边集为 \(T\) ,找到 \(edge(u,v)\in T\) ,使得 \(dis[v]=dis[u]+w(u,v)\) 就好了。

\(v\) 点的话,在 \(Dijkstra\) 中直接计数就行了。

注意: \(M\) 一定要设为 \(N*N\) 而不是 \(N*N/2\) !!!用 C++(NOI) 编译会显示超时,这可把我坑惨了......

代码

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1003
#define M N*N
#define il inline
#define re register
#define INF 0x3f3f3f3f
#define tie0 cin.tie(0),cout.tie(0)
#define fastio ios::sync_with_stdio(false)
#define File(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
typedef long long ll;

template <typename T> inline void read(T &x) {
	T f = 1; x = 0; char c;
    for (c = getchar(); !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for ( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
    x *= f;
}

const ll mod = (1ll << 31) - 1ll;

struct edge {
	int to, nxt, v;
} e[M];

int n, m;
ll ret = 1;
int head[M], cnt;
int d[N], ans[N];
bool vis[N];

void insert(int u, int v, int w) {
	e[++cnt].to = v, e[cnt].nxt = head[u], e[cnt].v = w, head[u] = cnt;
}

void Dijkstra() {
	for (int i = 2; i <= n; ++i) d[i] = INF;
	priority_queue < pair<int, int> > q;
	q.push(make_pair(0, 1));
	while (!q.empty()) {
		int u = q.top().second; q.pop();
		if (vis[u]) continue;
		vis[u] = 1;
		for (int i = head[u]; i; i = e[i].nxt) {
			int v = e[i].to, w = e[i].v;
			if (d[u] + w < d[v]) {
				d[v] = d[u] + w; ans[v] = 1;
				q.push(make_pair(-d[v], v));
			}
			else if (d[u] + w == d[v]) ans[v]++;
		}
	}
}

int main() {
	int u, v, w;
	read(n), read(m);
	for (int i = 1; i <= m; ++i) {
		read(u), read(v), read(w);
		insert(u, v, w), insert(v, u, w);
	}
	Dijkstra();
	for (int i = 1; i <= n; ++i)
		if (ans[i])
			ret = ret * ans[i] % mod;
	printf("%lld", ret);
	return 0;
}
posted @ 2020-02-04 18:56  小蒟蒻hlw  阅读(204)  评论(0)    收藏  举报