[luoguP3953] 逛公园(DP + spfa)

传送门

 

看到求方案数,应该很容易想到dp

f[u][i]表示到点u,且比到u的最短距离多i的方案数

那么需要先预处理dis数组,spfa或者堆优化的dijk

因为考虑到dp的顺序,f[u][i]转移到f[v][j]时,j不可能小于i

所以需要从0到k枚举i,然后从最后一个点开始记忆化搜索

至于判断0环,只需要在记忆化搜索的时候加一个栈即可

 

1A的代码,哈哈

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define N 200001

using namespace std;

int T, n, m, k, p, cnt, cnt1, ans;
int head[N], to[N], nex[N], val[N], head1[N], to1[N], nex1[N], val1[N], f[N][51], dis[N];
bool flag, vis[N], vis1[N][51], ins[N][51];
queue <int> q;

inline int read()
{
	int x = 0, f = 1;
	char ch = getchar();
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
	for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
	return x * f;
}

inline void add(int x, int y, int z)
{
	to[cnt] = y;
	val[cnt] = z;
	nex[cnt] = head[x];
	head[x] = cnt++;
}

inline void add1(int x, int y, int z)
{
	to1[cnt1] = y;
	val1[cnt1] = z;
	nex1[cnt1] = head1[x];
	head1[x] = cnt1++;
}

inline void spfa()
{
	int i, v, u;
	q.push(1);
	dis[1] = 0;
	while(!q.empty())
	{
		u = q.front();
		q.pop();
		vis[u] = 0;
		for(i = head[u]; ~i; i = nex[i])
		{
			v = to[i];
			if(dis[v] > dis[u] + val[i])
			{
				dis[v] = dis[u] + val[i];
				if(!vis[v])
				{
					q.push(v);
					vis[v] = 1;
				}
			}
		}
	}
}

inline void init()
{
	int i, x, y, z;
	n = read();
	m = read();
	k = read();
	p = read();
	for(i = 1; i <= m; i++)
	{
		x = read();
		y = read();
		z = read();
		add(x, y, z);
		add1(y, x, z);
	}
	spfa();
	f[1][0] = 1;
}

inline void clear()
{
	cnt = cnt1 = ans = flag = 0;
	memset(head, -1, sizeof(head));
	memset(head1, -1, sizeof(head1));
	memset(vis, 0, sizeof(vis));
	memset(dis, 127, sizeof(dis));
	memset(f, 0, sizeof(f));
	memset(vis1, 0, sizeof(vis1));
	memset(ins, 0, sizeof(ins));
}

inline int dfs(int u, int i)
{
	int j, v;
	if(i < 0 || flag) return 0;
	if(ins[u][i]) return flag = 1;
	if(vis1[u][i]) return f[u][i];
	ins[u][i] = 1;
	for(j = head1[u]; ~j; j = nex1[j])
	{
		v = to1[j];
		f[u][i] = (f[u][i] + dfs(v, dis[u] + i - val1[j] - dis[v])) % p;
	}
	vis1[u][i] = 1;
	ins[u][i] = 0;
	return f[u][i];
}

inline int solve()
{
	int i, t;
	for(i = 0; i <= k; i++)
	{
		t = dfs(n, i);
		if(flag) return -1;
		ans = (ans + t) % p;
	}
	return ans;
}

int main()
{
	T = read();
	while(T--)
	{
		clear();
		init();
		printf("%d\n", solve());
	}
	return 0;
}

  

posted @ 2017-12-29 09:34  zht467  阅读(166)  评论(0)    收藏  举报