zoukankan      html  css  js  c++  java
  • [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
    ", solve());
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    SSL JudgeOnline 1194——最佳乘车
    SSL JudgeOnline 1457——翻币问题
    SSL JudgeOnlie 2324——细胞问题
    SSL JudgeOnline 1456——骑士旅行
    SSL JudgeOnline 1455——电子老鼠闯迷宫
    SSL JudgeOnline 2253——新型计算器
    SSL JudgeOnline 1198——求逆序对数
    SSL JudgeOnline 1099——USACO 1.4 母亲的牛奶
    SSL JudgeOnline 1668——小车载人问题
    SSL JudgeOnline 1089——USACO 1.2 方块转换
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/8142822.html
Copyright © 2011-2022 走看看