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

    小结:

    流氓特判有点强。

  • 相关阅读:
    VisualSVN-Server windows 版安装时报错 "Service 'VisualSVN Server' failed to start. Please check VisualSVN Server log in Event Viewer for more details."
    Pytest 单元测试框架之初始化和清除环境
    Pytest 单元测试框架入门
    Python(email 邮件收发)
    Python(minidom 模块)
    Python(csv 模块)
    禅道简介
    2020年最好的WooCommerce主题
    Shopify网上开店教程(2020版)
    WooCommerce VS Magento 2020:哪个跨境电商自建站软件更好?
  • 原文地址:https://www.cnblogs.com/Hansue/p/11153163.html
Copyright © 2011-2022 走看看