• NOIP 2017 逛公园


    题目链接

    https://www.luogu.org/problemnew/show/P3953

     

    觉得是dp,想了一个n*最短路长度的dp

    发现数组开不下……

    而且我也不知道怎么在图上做dp

     

    然后就写了个K=0的情况,写了个最短路计数,水了30分

    同时写了个spfa判环,但是因为是多组数据所以没得分

     

    奋战了大概5 6 个小时,终于把这道题弄透并AC

    为什么效率怎么低……

    我应该自己画图理解,试着把思路讲出来,理解透这个过程,然后AC也就是理所当然的事情了

     

    具体思路网上一大把,我讲几个非常精彩的地方

    (1)看到k比较小,所以可以把k当作状态的一维, dp[u][k]表示从n走到u比最短路多走k的方案数

    (2)反向边可以用结构体套结构体的方式写,非常秀

    (3)判断有没有环的时候注意是再搜到一次,同时在栈里面

    (4)注意初始化是正向图,dp是反向图,这样连起来恰好构成一条从1到n的路径

    (5)网上很多题解写的是建立反向图防止跑到到不了n的点浪费时间

    但是如果建反向图的话岂不是会跑到到不了1的点浪费时间???

    所以建立反向图是为了和从1出发的最短路构成一条从1到n的路径

    其实正向图,然后最短路是从n开始出发,也一样。

    (5)然后主函数dfs只用写一次就好了,一次就能把所有的值算出来,看到很多代码是枚举k的

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    const int MAXN = 1e5 + 10;
    int d[MAXN], n, p, m, k;
    int dp[MAXN][60], vis[MAXN][60];
    
    struct graph
    {
        struct Edge { int to, w, next; };
        Edge e[MAXN << 1];
        int head[MAXN], tot;
        
        inline void init() { memset(head, -1, sizeof(head)); tot = 0; }
        
        inline void AddEdge(int from, int to, int w)
        {
            e[tot] = Edge{to, w, head[from]};
            head[from] = tot++;
        }
    }G[2];
    
    void read(int& x)
    {
        int f = 1; x = 0; char ch = getchar();
        while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); }
        while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
        x *= f;
    }
    
    struct node
    {
        int id, w;
        bool operator < (const node& rhs) const
        {
            return w > rhs.w;
        }
    };
    
    void dijkstra()
    {
        priority_queue<node> q;
        q.push(node{1, 0});
        _for(i, 1, n) d[i] = i == 1 ? 0 : 1e9;
        
        while(!q.empty())
        {
            node x = q.top(); q.pop();
            if(x.w != d[x.id]) continue;
            int u = x.id;
            
            for(int i = G[0].head[u]; ~i; i = G[0].e[i].next)
            {
                int v = G[0].e[i].to, w = G[0].e[i].w;
                if(d[v] > d[u] + w)
                {
                    d[v] = d[u] + w;
                    q.push(node{v, d[v]});
                }
            }
        }
    }
    
    int dfs(int u, int k)
    {
        if(vis[u][k]) return -1;
        if(dp[u][k] != -1) return dp[u][k];
        vis[u][k] = 1;
        
        int sum = 0;
        for(int i = G[1].head[u]; ~i; i = G[1].e[i].next)
        {
            int v = G[1].e[i].to, w = G[1].e[i].w, kk, t;
            kk = k - (d[v] + w - d[u]);
            if(kk < 0) continue;
            if((t = dfs(v, kk)) == -1) return -1;
            sum = (sum + t) % p;
        }
        if(u == 1) sum++;
        
        vis[u][k] = 0;
        return dp[u][k] = sum % p;
    }
    
    int main()
    {
        int T; read(T);
        while(T--)
        {
            G[0].init(); G[1].init();
            memset(dp, -1, sizeof(dp));
            memset(vis, 0, sizeof(vis));
            
            read(n); read(m); read(k); read(p);
            _for(i, 1, m)
            {
                int u, v, w; read(u); read(v), read(w);
                G[0].AddEdge(u, v, w);
                G[1].AddEdge(v, u, w);
            }
            
            dijkstra();
            printf("%d
    ", dfs(n, k));
        }
        
        return 0;
    }
  • 相关阅读:
    6 开发工具IDE-pycharm
    5 循环控制
    react native 遇到的坑
    代码缩略图插件
    JEECMS-自定义标签[list]
    Jeecms自定义标签用法[单个内容]
    ReactNative环境搭建
    修改浏览器accept使支持@ResponseBody
    [转]MyEclipse for Spring2014破解
    js正则验证手机号
  • 原文地址:https://www.cnblogs.com/sugewud/p/9881888.html
Copyright © 2020-2023  润新知