zoukankan      html  css  js  c++  java
  • NOIP2017 Day1 T3 逛公园(最短路+拓扑排序+DP)

      神tm比赛时多清个零就有60了T T

      首先跑出1起点和n起点的最短路,因为k只有50,所以可以DP。设f[i][j]表示比最短路多走i的长度,到j的方案数。

      我们发现如果在最短路上的和零边会有后向性,怎么办呢?拓扑排序。

      把最短路上的点和零边的点拉出来跑拓扑排序,如果有零环的话必定度数不为0,而且要注意零环必须在<=最短路+k的路径上才输出-1,这个就用刚刚跑出来的1起点到n起点的最短路来判断就好了。

      然后先按拓扑序DP出i相同的,然后再DP不在最短路上或者零边的。

    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<queue>
    #define MOD(x) ((x)>=mod?(x)-mod:(x))
    using namespace std;
    const int maxn=1000010;
    struct tjm{int too, dis, pre;}e[2][maxn];
    struct poi{int x, dis;};
    priority_queue<poi>q;
    bool operator<(poi a, poi b){return a.dis>b.dis;}
    int T, x, y, z, n, m, K, mod, top, tot[2], ans;
    int f[60][maxn], dist[2][maxn], last[2][maxn], d[maxn], st[maxn];
    void read(int &k)
    {
        int f=1; k=0; char c=getchar();
        while(c<'0' || c>'9') c=='-' && (f=-1), c=getchar();
        while(c<='9' && c>='0') k=k*10+c-'0', c=getchar();
        k*=f;
    }
    inline void add(int x, int y, int z, int ty){e[ty][++tot[ty]]=(tjm){y, z, last[ty][x]}; last[ty][x]=tot[ty];}
    inline void dij(int x, int ty)
    {
        memset(dist[ty], 32, sizeof(dist[ty]));
        dist[ty][x]=0; q.push((poi){x, 0});
        while(!q.empty())
        {
            poi now=q.top(); q.pop();
            if(dist[ty][now.x]!=now.dis) continue;
            for(int i=last[ty][now.x], too;i;i=e[ty][i].pre)
            if(dist[ty][too=e[ty][i].too]>dist[ty][now.x]+e[ty][i].dis)
            {
                dist[ty][too]=dist[ty][now.x]+e[ty][i].dis;
                q.push((poi){too, dist[ty][too]});
            }
        }
    }
    inline bool topo()
    {
        memset(d, 0, sizeof(d));
        for(int i=1;i<=n;i++)
        for(int j=last[0][i], too;j;j=e[0][j].pre)
        if(dist[0][i]+e[0][j].dis==dist[0][too=e[0][j].too]) d[too]++;
        top=0; for(int i=1;i<=n;i++) if(!d[i]) st[++top]=i;
        for(int i=1;i<=top;i++)
        for(int j=last[0][st[i]], too;j;j=e[0][j].pre)
        if(dist[0][st[i]]+e[0][j].dis==dist[0][too=e[0][j].too])
        {
            d[too]--;
            if(!d[too]) st[++top]=too;
        }
        for(int i=1;i<=n;i++) if(d[i] && dist[0][i]+dist[i][n]<=dist[0][n]+K) return 0;
        return 1;
    }
    int main()
    {
        read(T);
        while(T--)
        {
            memset(last, 0, sizeof(last)); tot[0]=tot[1]=0; 
            read(n); read(m); read(K); read(mod);
            for(int i=1;i<=m;i++) read(x), read(y), read(z), add(x, y, z, 0), add(y, x, z, 1);
            dij(1, 0); dij(n, 1);
            if(!topo()) {puts("-1"); continue;}
            memset(f, 0, sizeof(f)); f[0][1]=1; ans=0;
            for(int i=0;i<=K;i++)
            {
                for(int j=1;j<=top;j++) 
                for(int k=last[0][st[j]], too;k;k=e[0][k].pre)
                if(e[0][k].dis+dist[0][st[j]]==dist[0][too=e[0][k].too])
                f[i][too]+=f[i][st[j]], f[i][too]=MOD(f[i][too]);
                for(int j=1;j<=n;j++)
                for(int k=last[0][j], too, tmp;k;k=e[0][k].pre)
                if((tmp=i+e[0][k].dis+dist[0][j]-dist[0][too=e[0][k].too])<=K && i!=tmp)
                f[tmp][too]+=f[i][j], f[tmp][too]=MOD(f[tmp][too]);
                ans+=f[i][n]; ans=MOD(ans);
            }
            printf("%d
    ", ans);
        }
    }
    View Code

     

  • 相关阅读:
    /etc/init.d/functions详解[转]
    把linux可执行程序做成一个服务[转]
    Centos下Subversion 服务器安装配置(转)
    经典面试编程题atoi()实现
    asp.net mvc 模型绑定 从简单类型到泛型集合
    C# 编译器 csc 简单用法
    js 操作文本框中光标位置
    简洁的lambda表达式
    iphone safari不支持position fixed的解决办法
    List排序函数Sort
  • 原文地址:https://www.cnblogs.com/Sakits/p/8053326.html
Copyright © 2011-2022 走看看