【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));
    }
}
原文地址:https://www.cnblogs.com/Orz-IE/p/12039481.html