【題解】LuoGu3953:逛公園

原題傳送門
NOIp2017tgD1T3NOIp2017tgD1T3
當然是先跑個dijkstradijkstra把最短路求出來
然後想到dp求答案
dpu,ddp_{u,d}表示到uu路程爲dd方案數
狀態太多,看到K<=50K<=50
更改狀態dpu,ddp_{u,d}表示路程爲disu+ddis_u+d的方案數(disudis_u表示到uu的最短路)
然後用加法原理轉移

需要從最終態nn跑到最初態11所以跑反圖
直接拓撲上跑好像很麻煩,用記憶化dfsdfs
考慮一下-1的情況,就是0環的情況,開一個flagu,dflag_{u,d}的數組,如果重複到這個狀態兩遍就說明有0環

Code:

#include <bits/stdc++.h>
#define maxn 200010
#define maxm 51
using namespace std;
struct node{
	int val, dis;
	bool operator < (const node &x) const{ return x.dis < dis; }
};
priority_queue <node> q;
struct Edge{
	int to, next, len;
}edge[maxn << 1], edge2[maxn << 1];
int num, num2, head[maxn], head2[maxn], dis[maxn], vis[maxn], flag[maxn][maxm], dp[maxn][maxm], n, m, K, P;

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

void addedge(int x, int y, int z){ edge[++num] = (Edge){y, head[x], z}, head[x] = num; }
void addedge2(int x, int y, int z){ edge2[++num2] = (Edge){y, head2[x], z}, head2[x] = num2; }

void dijkstra(){
	memset(vis, 0, sizeof(vis));
	for (int i = 1; i <= n; ++i) dis[i] = 1e9; dis[1] = 0;
	q.push((node){1, 0});
	while (!q.empty()){
		node tmp = q.top(); q.pop();
		int u = tmp.val, l = tmp.dis;
		if (vis[u]) continue;
		vis[u] = 1;
		for (int i = head[u]; i; i = edge[i].next){
			int v = edge[i].to;
			if (dis[v] > dis[u] + edge[i].len){
				dis[v] = dis[u] + edge[i].len;
				if (!vis[v]) q.push((node){v, dis[v]});
			}
		}
	}
}

int dfs(int u, int l){
	if (l < 0 || l > K) return 0;
	if (flag[u][l]) return -1;
	if (dp[u][l] != -1) return dp[u][l];
	flag[u][l] = 1;
	int sum = 0;
	for (int i = head2[u]; i; i = edge2[i].next){
		int v = edge2[i].to;
		int tmp = dfs(v, dis[u] + l - dis[v] - edge2[i].len);
		if (tmp == -1) return -1;
		(sum += tmp) %= P;
	}
	if (u == 1 && !l) ++sum;
	dp[u][l] = sum;
	flag[u][l] = 0;
	return sum;
}

int main(){
	int Q = read(); 
	while (Q--){
		num = num2 = 0;
		memset(head, 0, sizeof(head));
		memset(head2, 0, sizeof(head2));
		n = read(), m = read(), K = read(), P = read();
		for (int i = 1; i <= m; ++i){
			int x = read(), y = read(), z = read();
			addedge(x, y, z);
			addedge2(y, x, z);
		}
		dijkstra();
		memset(dp, 255, sizeof(dp));
		memset(flag, 0, sizeof(flag));
		int ans = 0, flag = 0;
		for (int i = 0; i <= K; ++i){
			int tmp = dfs(n, i);
			if (tmp == -1){
				flag = 1; break;
			}
			(ans += tmp) %= P;
		}
		if (!flag) printf("%lld\n", ans); else puts("-1");
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章