• luogu_P3953 逛公园 记忆化搜索+最短路


    luogu_P3953 逛公园

    记忆化搜索+最短路


    题目链接
    边权有0而且可能有环,所以可能出0环
    出0环的话就有无限条路径了(因为可以绕着这个环一直转悠)
    所以先正着跑spfa
    然后反向建边
    记忆化搜索
    (f[i][j])表示到(i)点,还有比最短路增加(j)的余额的方案数。
    真不好理解
    再记录一个(vis[i][j])数组,(i),(j)的意义相同
    但是这个存的是0/1,表示是不是之前访问过
    假如之前访问过必然是0环(因为j没有减小)
    向下转移的就是(j+dis[x]-dis[y]-len(x,y))
    表示用(x)(y)之间的边代替最短路他们之间的距离能消耗多少(j)
    又不好理解
    看代码吧


    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    int T;
    namespace wk{
    const int maxk=60,maxn=100010;
    int n,m,k,p,dis[maxn],inq[maxn],vis[maxn][maxk],f[maxn][maxk];
    struct node{
        int to,dis;
        node(){}
        node(int _to,int _dis){to=_to;dis=_dis;}
    };
    vector<node> tu[maxn],ftu[maxn];
    //DP
    inline int dp(int now,int ls){
        int res=0;
        if(ls<0 || ls>k) return 0;
        if(vis[now][ls]){
            vis[now][ls]=0;return -1;
        }
        if(~f[now][ls]) return f[now][ls];
        vis[now][ls]=1;
        for(int i=0;i<ftu[now].size();i++){
            int y=ftu[now][i].to,z=ftu[now][i].dis;
            int val=dp(y,dis[now]+ls-dis[y]-z);
            if(val==-1){
                vis[now][ls]=0;return -1;
            }
            (res+=val)%=p;
        }
        vis[now][ls]=0;
        if(now==1 && ls==0) res++;
        f[now][ls]=res;
        return res;
    }
    void main(){
        scanf("%d%d%d%d",&n,&m,&k,&p);memset(f,-1,sizeof(f));
        for(int i=1;i<=n;i++) tu[i].clear(),ftu[i].clear();
        for(int x,y,c,i=1;i<=m;i++){
            scanf("%d%d%d",&x,&y,&c);
            tu[x].push_back(node(y,c));ftu[y].push_back(node(x,c));
        }
        //spfa
        memset(dis,0x3f,sizeof(dis));memset(inq,0,sizeof(inq));
        queue<int> q;q.push(1);dis[1]=0;inq[1]=1;
        while(q.size()){
            int x=q.front();q.pop();inq[x]=0;
            for(int i=0;i<tu[x].size();i++){
                int y=tu[x][i].to,z=tu[x][i].dis;
                if(dis[y]>dis[x]+z){
                    dis[y]=dis[x]+z;
                    if(!inq[y]){
                        q.push(y);inq[y]=1;
                    }
                }
            }
        }
        int ans=0;
        for(int i=0;i<=k;i++){
            int now=dp(n,i);
            if(now==-1){printf("-1
    ");return;}
            (ans+=now)%=p;
        }
        printf("%d
    ",ans);
        return;
    }
    }
    int main()
    {
        scanf("%d",&T);while(T--){wk::main();}
        return 0;
    }
    
  • 相关阅读:
    TCP 协议如何保证可靠传输
    mysql 优化
    Navicat 导入导出
    Hibernate的优缺点
    寒假学习日报(十八)
    《机器学习十讲》第二讲总结
    寒假学习日报(十七)
    《设计原本》阅读笔记(二)
    《机器学习十讲》第一讲总结
    寒假学习日报(十六)
  • 原文地址:https://www.cnblogs.com/ChrisKKK/p/11629747.html
Copyright © 2020-2023  润新知