P3953 逛公园

P3953 逛公园

毒瘤的noip2017

不过今年再来看。感觉容易许多。不再是无从下手了、希望今年也是吧


第一天的dp? 就是这个。

看到k值不大,而且对答案有影响。那么就需要记录。
来看k的意义,是说比最短路多k。启示我们要求最短路。
可以类比一下\(A^*\)求k短路。先反向跑一边最短路作为估价函数,然后在正向跑。

这个题也可以如此做。只不过成了k短路计数。

然后dp的状态就很容易设计出来了。

\(f[i][j]\)表示从起点到了i这个点,多走了j的冤枉路。

转移呢,就是根据相邻两点分别到终点的最短路,计算又多走了多少的冤枉路。然后加进答案里。

那么无限多中答案是为什么呢?很容易就想到了零环。

然后如何判断零环呢? 方法很多,可以预先跑dfs,拓扑排序,或者是在记忆化搜索时检查是否在栈中。

这里使用了拓扑排序(其实另外两个都试过,调了好久,没有错,最后发现,领接表忘清零了。拓扑排序是最后一个写的233)

只计算零边的对点产生的度数。然后把所有点压进容器(写法不同),然后只拓展零边。最后看是否所有点都被访问过。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
using std::queue;
const int maxn=101000;
struct node
{
    int p;
    int value;
    int nxt;
};
int h[maxn],H[maxn],tail;
node l[maxn<<2],L[maxn<<5];
int dis[maxn];
int n,m,k;
long long p;
bool inque[maxn];
void add(int a,int b,int c)
{
    ++tail;
    l[tail].p=b;
    l[tail].value=c;
    l[tail].nxt=h[a];
    h[a]=tail;
    L[tail].p=a;
    L[tail].value=c;
    L[tail].nxt=H[b];
    H[b]=tail;
}
void spfa()
{
    memset(dis,127,sizeof(dis));
    queue<int>q;
    q.push(1);inque[1]=true;dis[1]=0;
    while(!q.empty())
    {
        int pas=q.front();q.pop();
        inque[pas]=false;
        for(int i=h[pas];i;i=l[i].nxt)
        {
            int v=l[i].p;
            if(dis[v]>dis[pas]+l[i].value)
            {
                dis[v]=dis[pas]+l[i].value;
                if(!inque[v])
                {
                    inque[v]=true;
                    q.push(v);
                }
            }
        }
    }
}
int ind[maxn];
bool vis[maxn];
bool topsort()
{
    queue<int>q;
    for(int i=1;i<=n;i++)   if(!ind[i]) q.push(i);
    while(!q.empty())
    {
        int pas=q.front();q.pop();
        vis[pas]=true;
        for(int i=h[pas];i;i=l[i].nxt)
            if(!l[i].value&&!vis[l[i].p])
            {
                int v=l[i].p;
                ind[v]--;
                if(!ind[v])
                    q.push(v);
            }
    }
    bool F=true;
    for(int i=1;i<=n;i++)
        if(!vis[i])
            F=false;
    return F;
}
long long f[maxn][60];
int dfs(int now,int K)
{
    if(f[now][K]!=-1)   return f[now][K];
    f[now][K]=0;
    for(int i=H[now];i;i=L[i].nxt)
    {
        int v=L[i].p;
        int nxt=K-(dis[v]+L[i].value-dis[now]);
        if(nxt<0||nxt>k)    continue;
        f[now][K]=(f[now][K]+dfs(v,nxt))%p;
    }
    return f[now][K];
}
void init()
{
    memset(inque,0,sizeof(inque));
    memset(vis,0,sizeof(vis));
    //memset(V,0,sizeof(V));
    memset(f,-1,sizeof(f));
    memset(h,0,sizeof(h));
    memset(H,0,sizeof(H));
    memset(ind,0,sizeof(ind));
    //tail=0;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d%d%d%lld",&n,&m,&k,&p);
        int a,b,c;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            if(!c)  ind[b]++;
        }
        if(!topsort())
        {
            printf("-1\n");
            continue;
        }
        spfa();
        long long ans=0;
        f[1][0]=1;
        for(int i=0;i<=k;i++)
            ans=(ans+dfs(n,i))%p;
        printf("%lld\n",ans);

    }
}
posted @ 2018-10-30 09:38  Lance1ot  阅读(208)  评论(0编辑  收藏  举报