• [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;
    }
    

      

  • 相关阅读:
    Linux文件系统属性权限chattr与lsattr命令
    Linux权限管理之ACL权限
    慈悲
    存在的四个象限
    白细胞低的原因
    释放能量和注意力
    [C#] 走进异步编程的世界
    改变世界的工程师:荣耀背后深刻着孤独
    分享基于EF+MVC+Bootstrap的通用后台管理系统及架构(转)
    如何拿到半数面试公司Offer——我的Python求职之路(转)
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/8142822.html
Copyright © 2020-2023  润新知