• 【NOIP2017】逛公园 D1 T3


    记忆化搜索

    跑一次反向的最短路求出MinDis(u,n)MinDis(u,n)

    f[u][k]f[u][k]表示dis(u,n)<=MinDis(u,n)+dis(u,n)<=MinDis(u,n)+kdis(u,n)<=MinDis(u,n)+dis(u,n)<=MinDis(u,n)+k的方案数,答案就是f[1][K]f[1][K]

    考虑egde(u,v,w)egde(u,v,w)
    同样的道理走这条边的话, dis(v,n)=MinDis(v,n)+wMinDis(u,n)dis(v,n)=MinDis(v,n)+w-MinDis(u,n)
    f[u][k]=f[v][k(MinDis(v,n)MinDis(u,n)+w)]f[u][k]=∑f[v][k-(MinDis(v,n)-MinDis(u,n)+w)]
    f[u][k]=f[v][k(MinDis(v,n)MinDis(u,n)+w)]f[u][k]=∑f[v][k−(MinDis(v,n)−MinDis(u,n)+w)]
    这样怎么判00环呢?只要在搜索的时候记录个instackinstackokok

    如果当前的转状态还在搜索的栈中就可以直接返回1-1

    AC code:

    #include<bits/stdc++.h>
    using namespace std;
     
    inline void read(int &num)
    {
        char ch; int flag=1;
        while(!isdigit(ch=getchar()))if(ch=='-')flag=-flag;
        for(num=ch-'0';isdigit(ch=getchar());num=num*10+ch-'0');
        num*=flag;
    }
     
    const int MAXN = 100005;
    const int MAXM = 200005;
    const int MAXK = 55;
     
    int n, m, k, p, f[MAXN][MAXK];
    bool instk[MAXN][MAXK];
     
    int fir[MAXN], to[MAXM], nxt[MAXM], wt[MAXM], cnt;
    int rfir[MAXN], rto[MAXM], rnxt[MAXM], rwt[MAXM], rcnt;
     
    inline void Add(int u, int v, int w) { to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt; wt[cnt] = w; }
    inline void rAdd(int u, int v, int w) { rto[++rcnt] = v; rnxt[rcnt] = rfir[u]; rfir[u] = rcnt; rwt[rcnt] = w; }
     
    int dis[MAXN];
    bool inq[MAXN];
    queue<int>Q;
    void spfa(int T)
    {
        memset(dis, 0x7f, sizeof dis);
        dis[T] = 0; inq[T] = 1; Q.push(T);
        while(!Q.empty())
        {
            int u = Q.front(); inq[u] = 0; Q.pop();
            for(int i = rfir[u]; i; i = rnxt[i])
                if(dis[rto[i]] > dis[u] + rwt[i])
                {
                    dis[rto[i]] = dis[u] + rwt[i];
                    if(!inq[rto[i]])
                        inq[rto[i]] = 1, Q.push(rto[i]);
                }
        }
    }
     
    int dfs(int u, int now)
    {
        if(instk[u][now]) return -1;
        if(f[u][now]) return f[u][now];
        instk[u][now] = 1;
        if(u == n) f[u][now] = 1;
        for(int i = fir[u], tmp; i; i = nxt[i])
            if(dis[to[i]]-dis[u]+wt[i] <= now)
            {
                if((tmp=dfs(to[i], now-dis[to[i]]+dis[u]-wt[i])) == -1) return f[u][now] = -1;
                (f[u][now] += tmp) %= p;
            }
        return instk[u][now] = 0, f[u][now];
    }
     
    int main ()
    {
        int T, x, y, z;
        read(T);
        while(T--)
        {
            memset(f, 0, sizeof f);
            memset(instk, 0, sizeof instk);
            memset(fir, 0, sizeof fir); cnt = 0;
            memset(rfir, 0, sizeof fir); rcnt = 0;
            read(n), read(m), read(k), read(p);
            for(int i = 1; i <= m; i++)
            {
                read(x), read(y), read(z);
                Add(x, y, z), rAdd(y, x, z);
            }
            spfa(n);
            printf("%d
    ", dfs(1, k));
        }
    }
    
  • 相关阅读:
    JUnit中的设计模式:组合模式 Composite
    Activity在屏幕显示的方向切换
    Jenkins插件之有用
    Jenkins插件之Dashboard和wall display
    python技巧32[常用技巧集]
    Jenkins插件之构建与MSBuild
    Jenkins插件之Publish Over SSH/CIFS/FTP
    使用devenv/MSBuild在命令行编译单个project
    Jenkins中执行batch和Python
    python翻译[排序高级]
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039481.html
Copyright © 2020-2023  润新知