• noip2017d1t3


    其实是参考洛谷上某篇题解的思路;

    先求出两个dis数组表示从1走和从n走的最短路;

    转移方程:dp[v][dis1[u]-dis1[v]+w+j]+=dp[u][j];

    转移顺序要注意一下呢,肯定是先枚举第二维;

    dis1[u]-dis1[v]+w+j>=j;

    因为有等号,即有同层之间的转移,第一维也不能随便枚举;

    如果没有0边,我们可以考虑按dis1从小到大枚举,和dijkstra很像,可以保证更新顺序是对的;

    有了零边就要考虑连续好几个零边之间的转移,这个可以把0边挑出来拓扑排序;

    关于-1的判断,把零边挑出来之后是可以知道那些点是在零环中的,再看一下经过这个点的路径有没有满足条件的就好了。

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    using namespace std;
    typedef long long ll;
    const int maxn=100010;
    const ll inf=1e12;
    ll dp[maxn][55],dis[maxn][2];
    struct edg{
        int nex,to;
        ll w;
    }e[maxn*2][2];
    struct node{
        int id;
        ll dis;
        bool operator<(const node&a)const{
            return dis>a.dis;
        }
    }A,B;
    int s,flag,head,tail,t1,t2,vis[maxn],last[maxn][2],T,n,m,k,p,x,y,qq[maxn];
    int h[maxn],pre[maxn*2],other[maxn*2],t3,du[maxn],tot,in[maxn];
    ll z;
    priority_queue<node>q;
    void add3(int x,int y){++t3;pre[t3]=h[x];h[x]=t3;other[t3]=y;}
    void add1(int x,int y,ll z){++t1;e[t1][0].nex=last[x][0];last[x][0]=t1;e[t1][0].to=y;e[t1][0].w=z;}
    void add2(int x,int y,ll z){++t2;e[t2][1].nex=last[x][1];last[x][1]=t2;e[t2][1].to=y;e[t2][1].w=z;}
    void dijkstra(int lei){
        //lei=0,1为起点,lei=1,n为起点;
        while(!q.empty())q.pop();
        memset(vis,0,sizeof(vis));
        for(int i=0;i<=n;++i)dis[i][lei]=inf;
        if(!lei)s=1;else s=n;
        dis[s][lei]=0;
        A.id=s;A.dis=0;q.push(A);
        while(!q.empty()){
            B=q.top();q.pop();
            if(vis[B.id])continue;
            vis[B.id]=1;
            for(int i=last[B.id][lei];i;i=e[i][lei].nex){
                int v=e[i][lei].to;
                if(vis[v])continue;
                if(dis[v][lei]>dis[B.id][lei]+e[i][lei].w){
                    dis[v][lei]=dis[B.id][lei]+e[i][lei].w;
                    A.id=v;A.dis=dis[v][lei];
                    q.push(A);
                }
            }
        }
    }
    struct hehe{
        ll dis;
        int id,u;
        bool operator<(const hehe&a)const{
            if(dis==a.dis)return id<a.id;
            return dis<a.dis;
        }
    }lj[maxn];
    void tp(){
        for(int i=0;i<=n;++i){
            lj[i].dis=inf;
            lj[i].id=0;
        }
        flag=1;
        head=tail=0;
        for(int i=1;i<=n;++i)if(in[i]&&!du[i]){
            qq[++tail]=i;lj[i].id=tail;
        }
        while(head<tail){
            int u=qq[++head];
            for(int i=h[u];i;i=pre[i]){
                int v=other[i];
                du[v]--;
                if(!du[v]){qq[++tail]=v;lj[v].id=tail;}
            }
        }
        for(int i=1;i<=n;++i){
            if(in[i]&&du[i]){
                if(dis[i][1]+dis[i][0]<=dis[n][0]+k){
                    flag=0;
                }
            }
        }
    }
    int main(){
        cin>>T;
        while(T--){
            scanf("%d%d%d%d",&n,&m,&k,&p);
            t1=t2=t3=0;
            memset(last,0,sizeof(last));
            memset(du,0,sizeof(du));
            memset(in,0,sizeof(in));
            memset(dp,0,sizeof(dp));
            memset(h,0,sizeof(h));
            for(int i=1;i<=m;++i){
                scanf("%d%d%lld",&x,&y,&z);
                add1(x,y,z);add2(y,x,z);
                if(!z){add3(x,y);du[y]++;in[x]=in[y]=1;}
            }
            dijkstra(0);
            dijkstra(1);
            tp();
            if(!flag){puts("-1");continue;}
            else{
                for(int i=1;i<=n;++i){
                    lj[i].dis=dis[i][0];
                    lj[i].u=i;
                }
                sort(lj+1,lj+n+1);
                dp[1][0]=1;
                for(int j=0;j<=k;++j)
                  for(int i=1;i<=n;++i)
                  {
                      int u=lj[i].u;
                      for(int l=last[u][0];l;l=e[l][0].nex){
                          int v=e[l][0].to;
                          if(dis[u][0]-dis[v][0]+e[l][0].w+j<=k){
                            dp[v][dis[u][0]-dis[v][0]+e[l][0].w+j]+=dp[u][j];
                            if(dp[v][dis[u][0]-dis[v][0]+e[l][0].w+j]>=p)dp[v][dis[u][0]-dis[v][0]+e[l][0].w+j]-=p;
                        }
                    }
                }
                ll ans=0;
                for(int i=0;i<=k;++i){
                    ans+=dp[n][i];
                    if(ans>=p)ans-=p;
                }
                printf("%lld
    ",ans);
            }
        }
        //system("pause");
        return 0;
    }
    代码
  • 相关阅读:
    JDK1.8源码(四)——java.util.Arrays类
    JDK1.8源码(三)——java.lang.String类
    Java基础(六)——集合
    设计模式(二)——单例模式
    当你忘了数据库的设计语句,看这一篇就能拾起记忆
    MyBatis之配置优化
    Mybatis中的一些配置,直接拿来就可以用
    网络编程---ip&端口
    java基础数据类型小知识
    学习了MarkDown文本工具
  • 原文地址:https://www.cnblogs.com/dibaotianxing/p/7905979.html
Copyright © 2020-2023  润新知