zoukankan      html  css  js  c++  java
  • NOIP2017TG D1T3 逛公园

    题目链接

    题意:

    求有向图内$1$和$n$两点间路径计数,路径长度不超过最短路长度加$K$。

    程序1(30分):

    考虑记忆化搜索,设$dis_u$为点$n$到点$u$的最短路径长度,$f_{u,k}$表示$len(u,n)<=dis_u+k$的路径计数。

    那么对于一条边$(u,v,w)$,一次转移中“耗费”的“额外路程”

    $$len_{ex}=dis_v+w-dis_u$$

    没什么好说,边取模边叠加即可。

    考虑零环,发现等价于重复搜索,插旗即可。

    然而神秘错误导致RE,得到30分。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #define IL inline
    #define UI unsigned
    using namespace std;
    const int inf=2147483647;
    const int N=1e5;
    const int M=2e5;
    const int K=50;
    
        int T,n,m,k,p;
        
    struct Edge{
        int to,nxt,cap;
        
    }e[M+3],g[M+3];
        int h[N+3],top,l[N+3],tpp;
        
    void add(int u,int v,int w,Edge *e,int *h,int &top){
        top++;
        e[top].to=v;
        e[top].nxt=h[u];
        e[top].cap=w;
        h[u]=top;
        
    }
    
    struct Dat{
        int v,d;
        
        Dat(int a,int b)
            :v(a),d(b){}
        
    };    
    
    bool operator<(Dat a,Dat b){
        return a.d>b.d;
        
    }
    
        priority_queue<Dat>que;
        int dis[N+3];
    
    void dij(int S,Edge *e,int *h){
        for(int i=1;i<=n;i++)
            dis[i]=inf;
        dis[S]=0;
        que.push(Dat(S,0));
        
        while(!que.empty()){
            Dat x=que.top();
            que.pop();
            
            while(!que.empty()&&dis[x.v]<x.d){
                x=que.top();
                que.pop();
                
            }
            
            if(dis[x.v]<x.d)
                continue;
            
            int u=x.v;
            for(int i=h[u];~i;i=e[i].nxt){
                int v=e[i].to;
                
                if(dis[u]+e[i].cap<dis[v]){
                    dis[v]=dis[u]+e[i].cap;
                    que.push(Dat(v,dis[v]));
                    
                }
                
            }
            
        }
        
    }
    
        int f[N+3][K+3];
        bool vis[N+3][K+3];
        
    int mod(int x){
        if(x>=p)
            return x-p;
        return x;
        
    }
        
    int dfs(int u,int k){
        if(vis[u][k])
            return -1;
        
        if(f[u][k]>0)
            return f[u][k];
        
        vis[u][k]=1;
        if(u==n)
            f[u][k]=1;
        else 
            f[u][k]=0;
            
        for(int i=h[u];~i;i=e[i].nxt){
            int v=e[i].to;
            int tmp=dis[v]-dis[u]+e[i].cap;
            if(tmp<=k){
                int res=dfs(v,k-tmp);
                if(res==-1){
                    f[u][k]=-1;
                    return -1;
                    
                }
            
                f[u][k]=mod(f[u][k]+res);
                
            }
            
        }
        
        vis[u][k]=0;
        return f[u][k];
        
    }
    
    int main(){
        scanf("%d",&T);
        
        while(T--){
            scanf("%d%d%d%d",&n,&m,&k,&p);
            memset(h,-1,sizeof h);
            memset(l,-1,sizeof l);
            top=tpp=-1;
            for(int i=1;i<=m;i++){
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                add(x,y,z,e,h,top);
                add(y,x,z,g,l,tpp);
                
            }
            
            dij(n,g,l);
            
            memset(f,0,sizeof f);
            memset(vis,0,sizeof vis);
            
            printf("%d
    ",dfs(1,k));
            
        }
        
        return 0;
        
    }

    程序2(100分):

    思考RE来源,考虑越界爆栈,发现“额外路程”可能为负导致越界。

    于是加了一句话,成功AC。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    #define IL inline
    #define UI unsigned
    using namespace std;
    const int inf=2147483647;
    const int N=1e5;
    const int M=2e5;
    const int K=50;
    
        int T,n,m,k,p;
        
    struct Edge{
        int to,nxt,cap;
        
    }e[M+3],g[M+3];
        int h[N+3],top,l[N+3],tpp;
        
    void add(int u,int v,int w,Edge *e,int *h,int &top){
        top++;
        e[top].to=v;
        e[top].nxt=h[u];
        e[top].cap=w;
        h[u]=top;
        
    }
    
    struct Dat{
        int v,d;
        
        Dat(int a,int b)
            :v(a),d(b){}
        
    };    
    
    bool operator<(Dat a,Dat b){
        return a.d>b.d;
        
    }
    
        priority_queue<Dat>que;
        int dis[N+3];
    
    void dij(int S,Edge *e,int *h){
        for(int i=1;i<=n;i++)
            dis[i]=inf;
        dis[S]=0;
        que.push(Dat(S,0));
        
        while(!que.empty()){
            Dat x=que.top();
            que.pop();
            
            while(!que.empty()&&dis[x.v]<x.d){
                x=que.top();
                que.pop();
                
            }
            
            if(dis[x.v]<x.d)
                continue;
            
            int u=x.v;
            for(int i=h[u];~i;i=e[i].nxt){
                int v=e[i].to;
                
                if(dis[u]+e[i].cap<dis[v]){
                    dis[v]=dis[u]+e[i].cap;
                    que.push(Dat(v,dis[v]));
                    
                }
                
            }
            
        }
        
    }
    
        int f[N+3][K+3];
        bool vis[N+3][K+3];
        
    int mod(int x){
        if(x>=p)
            return x-p;
        return x;
        
    }
        
    int dfs(int u,int k){
        if(vis[u][k])
            return -1;
        
        if(f[u][k]>0)
            return f[u][k];
        
        vis[u][k]=1;
        if(u==n)
            f[u][k]=1;
        else 
            f[u][k]=0;
            
        for(int i=h[u];~i;i=e[i].nxt){
            int v=e[i].to;
            int tmp=dis[v]-dis[u]+e[i].cap;
            
            if(tmp<0)
                continue;
            
            if(tmp<=k){
                int res=dfs(v,k-tmp);
                if(res==-1){
                    f[u][k]=-1;
                    return -1;
                    
                }
            
                f[u][k]=mod(f[u][k]+res);
                
            }
            
        }
        
        vis[u][k]=0;
        return f[u][k];
        
    }
    
    int main(){
        scanf("%d",&T);
        
        while(T--){
            scanf("%d%d%d%d",&n,&m,&k,&p);
            memset(h,-1,sizeof h);
            memset(l,-1,sizeof l);
            top=tpp=-1;
            for(int i=1;i<=m;i++){
                int x,y,z;
                scanf("%d%d%d",&x,&y,&z);
                add(x,y,z,e,h,top);
                add(y,x,z,g,l,tpp);
                
            }
            
            dij(n,g,l);
            
            memset(f,0,sizeof f);
            memset(vis,0,sizeof vis);
            
            printf("%d
    ",dfs(1,k));
            
        }
        
        return 0;
        
    }

    小结:

    流氓特判有点强。

  • 相关阅读:
    【学习笔记】pip3 安装使用国内源
    【学习笔记】Team Explorer for Microsoft Visual Studio2015 安装时发生严重错误
    微信聊天记录长图 打印
    Go语言中用 os/exec 执行命令的五种姿势
    Python 代码调试神器:PySnooper
    终于来了!!Pyston v2.0 发布,解决 Python 慢速的救星
    超详细讲解如何使用 pdb 在服务器上调试代码
    超详细图文教你如何使用 PyCharm 进行远程调试
    最全的 pip 使用指南,50 % 你可能都没用过~
    学 Python 一定要学会的几个高阶函数
  • 原文地址:https://www.cnblogs.com/Hansue/p/11153163.html
Copyright © 2011-2022 走看看