[NOIP2017 TG D2T2]宝藏

题目大意:给定一个有重边,边有权值的无向图。从某一个点出发,求到达所有的点需要的最少费用,
并且限制两点之间只有一条路径。
费用的计算公式为:所有边的费用之和。而边$(x->y)$的费用就为:$y$到初始点的距离$\times$边权。

题解:记忆化搜索,$f[i][j]$表示第$i$个节点,比到这个点的最短多了$j$的方案数,在反图上跑就行了,如果一个点被访问时还在栈中,就有零环

卡点:无(但是可以构造数据卡$SPFA$)

C++ Code:(SFPA)

#include <cstdio>
#include <cstring>
#define maxn 100010
#define maxm 200010
using namespace std;
int Tim, n, m, k, P;
bool flag;
struct Edge {int to, nxt, w;};
struct Graph{
	int head[maxn], cnt;
	Edge e[maxm];
	void add(int a, int b, int c) {
		e[++cnt] = (Edge) {b, head[a], c}; head[a] = cnt;
	}
} G1, G2;
int dis[maxn], f[maxn][55];
int q[maxn << 2], h, t;
bool vis[maxn], s[maxn][55];
int dfs(int x, int num) {
	if (~f[x][num]) return f[x][num];
	int ans = 0, v, tmp;
	s[x][num] = true;
	for (int i = G2.head[x]; i; i = G2.e[i].nxt) {
		v = G2.e[i].to;
		tmp = dis[x] - dis[v] + num - G2.e[i].w;
		if (tmp < 0 || tmp > k) continue;
		if (s[v][tmp]) {
			flag = true;
			return 0;
		}
		ans = (ans + dfs(v, tmp)) % P;
		if (flag) return 0;
	}
	s[x][num] = false;
	return f[x][num] = ans;
}
int solve(int st) {
	memset(f, -1, sizeof f);
	int ans = 0; flag = false;
	f[st][st] = 1;
	for (int i = 0; i <= k; i++) {
		int tmp = dfs(n, i);
		ans = (ans + tmp) % P;
		if (flag) break;
	}
	if (flag) return -1;
	else return ans;
}
void SPFA(int st) {
	memset(dis, 0x3f, sizeof dis);
	memset(vis, false, sizeof vis);
	dis[q[h = t = 0] = st] = 0;
	while (h <= t) {
		int u = q[h++];
		vis[u] = false;
		for (int i = G1.head[u]; i; i = G1.e[i].nxt) {
			int v = G1.e[i].to;
			if (dis[v] > dis[u] + G1.e[i].w) {
				dis[v] = dis[u] + G1.e[i].w;
				if (!vis[v]) {
					vis[v] = true;
					q[++t] = v;
				}
			}
		}
	}
}
int main() {
	scanf("%d", &Tim); 
	while (Tim --> 0) {
		scanf("%d%d%d%d", &n, &m, &k, &P);
		for (int i = 0; i < m ; i++) {
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			G1.add(a, b, c);
			G2.add(b, a, c);
		}
		G1.add(0, 1, 0);
		G2.add(1, 0, 0);
		SPFA(0);
		printf("%d\n", solve(0));
		if (Tim) {
			G1.cnt = G2.cnt = 0;
			memset(G1.head, 0, sizeof G1.head);
			memset(G2.head, 0, sizeof G2.head);
			memset(s, false, sizeof s);
		}
	}
	return 0;
}

  

猜你喜欢

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