zoukankan      html  css  js  c++  java
  • P3953 逛公园

    传送门

    注意数据中 k <= 50,考虑从这里入手解决问题

    设 f [ i ] [ j ] 表示 已经到 i 点,最多还能比最短路程多走 j 的长度而不超过限制时的方案数

    处理出终点到每个点的最短路程 dis [ i ]

    那么对于一条边 (a,b,c), f [ a ] [ j ] --> f [ b ] [ j - (dis[a]-dis[b]+c) ]

    那么对于每一个状态

    如果直接DP顺序不好确定,所以考虑用记忆化搜索实现

    然后考虑判断无穷多的路线

    显然如果 dfs 时重复走到同一个状态说明出现了无穷多路线,所以开一个数组存一下当前走过的状态就好了

    求最短路用的是Dijkstra

    多组数据一定要记得清空

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<iostream>
    #include<queue>
    #include<vector>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=1e5+7,INF=0x3f3f3f3f;
    int T,n,m,K,mo;
    inline int fk(int x) { return x>=mo ? x-mo : x; }
    int fir[N],from[N<<2],to[N<<2],val[N<<2],cntt;//存正图
    inline void add(int &a,int &b,int &c)
    {
        from[++cntt]=fir[a];
        fir[a]=cntt; to[cntt]=b; val[cntt]=c;
    }
    vector <int> v[N],g[N];//存反图
    int dis[N];
    struct data
    {
        int pos,dis;
        inline bool operator < (const data &tmp) const {
            return dis>tmp.dis;
        }
    };
    priority_queue <data> q;
    void Dijk()//Dijkstra不解释
    {
        memset(dis,INF,sizeof(dis)); dis[n]=0; q.push((data){n,0});
        data x; int len;
        while(!q.empty())
        {
            x=q.top(); q.pop(); if(dis[x.pos]!=x.dis) continue;
            len=v[x.pos].size();
            for(int i=0;i<len;i++)
            {
                int u=v[x.pos][i],w=g[x.pos][i];
                if(dis[u]>x.dis+w) dis[u]=x.dis+w,q.push((data){u,dis[u]});
            }
        }
    }
    int f[N][57];
    bool vis[N][57],flag;
    void dfs(int x,int k)
    {
        if(flag) return;
        vis[x][k]=1; if(x==n) f[x][k]=1;//f[n][k]初始为1
        //注意不能初始把所有f[n][k]=1,因为是记忆化,如果初始有值就不会dfs下去,而f[n][k]最终可能有不止一种方案
        for(int i=fir[x];i;i=from[i])
        {
            int &v=to[i],w=k-(dis[v]-dis[x]+val[i]); if(w<0) continue;//判一下w是否符合限制
            if(vis[v][w])/*判断是否有无穷多的解*/ { flag=1; vis[x][k]=0; return; }//退出前记得vis=0
            if(!f[v][w]) dfs(v,w);
            f[x][k]=fk(f[x][k]+f[v][w]);//记忆化
        }
        vis[x][k]=0;
    }
    inline void clr()//初始化
    {
        memset(f,0,sizeof(f)); memset(fir,0,sizeof(fir));
        for(int i=1;i<=n;i++) v[i].clear(),g[i].clear();
        cntt=flag=0;
    }
    int main()
    {
        int a,b,c;
        T=read();
        while(T--)
        {
            n=read(); m=read(); K=read(); mo=read();
            clr();
            for(int i=1;i<=m;i++)
            {
                a=read(),b=read(),c=read();
                add(a,b,c); v[b].push_back(a); g[b].push_back(c);
            }
            Dijk();
            dfs(1,K);
            printf("%d
    ",flag ? -1 : f[1][K]);//最终答案是f[1][K]
        }
        return 0;
    }
  • 相关阅读:
    Spring快速开启计划任务
    一张图告诉你什么是系统架构师
    一张图搞清楚Java异常机制
    Spring Cloud配置中心内容加密
    Spring Cloud配置中心高可用搭建
    Spring Cloud动态刷新配置信息
    Spring Boot实现热部署
    Spring Boot集成Mybatis双数据源
    (1)python tkinter-窗体
    (1)html基础
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9904872.html
Copyright © 2011-2022 走看看