逛公园

Posted guodonglovesoi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了逛公园相关的知识,希望对你有一定的参考价值。

看到这题,我们不难想到一个dp,就是设F[i][j]为到达i节点比最短路多了j的方案总数.

但是我们发现这个状态根本没办法转移:i可以从任何一个有连边的节点转移.(有后效性)

所以我们倒着跑就好了 ~

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<map>
#include<queue>
#include<iostream>
#include<cmath>
//#define int long long 
using namespace std;
inline int gi(){char tmp=getchar();int flag=1;while(tmp<'0'||tmp>'9'){if(tmp=='-'){flag=-1;tmp=getchar();break;}tmp=getchar();}int ans=0;while(tmp<='9' and tmp>='0') {ans=ans*10+tmp-'0';tmp=getchar();}return ans*flag;}
inline void write(int x){static int stk[100], top = 0;if (x == 0) { putchar('0'); putchar(' ');return; }if (x < 0) { x = -x; putchar('-'); }while (x) { stk[++top] = x % 10; x /= 10; }while (top) { putchar(stk[top--] + '0'); }putchar(' ');}
#define line() putchar('
');
#define Mem(Arr,V) memset(Arr,V,sizeof Arr);
#define Mcpy(Arr,qwq) memcpy(Arr,qwq,sizeof qwq);
#define max3(a,b,c) max(max(a,b),c)
#define max4(a,b,c,d) max4(max3(a,b,c),d);
#define in(a) a=gi()
#define in2(a,b) in(a),in(b)
#define in3(a,b,c) in2(a,b),in(c)
#define in4(a,b,c,d) in3(a,b,c),in(d)
#define write2(a,b) write(a),write(b)
#define write3(a,b,c) write2(a,b),write(c)
#define write4(a,b,c,d) write3(a,b,c),write(d)
inline void smin(int &x,int y){x=min(x,y);}
inline void smax(int &x,int y){x=max(x,y);}
const int N = 1000001;
struct Edg{
    int v,w,nxt;
}Edge[N<<1];int cnt,Head[N];
inline void Add(int u,int v,int w){Edge[++cnt].v=v;Edge[cnt].w=w;Edge[cnt].nxt=Head[u];Head[u]=cnt;}
struct Rev{
    int v,w,nxt;
}Reverse[N<<1];int cnt1,Pre[N];
inline void Link(int u,int v,int w){Reverse[++cnt1].v=v;Reverse[cnt1].w=w;Reverse[cnt1].nxt=Pre[u];Pre[u]=cnt1;}
struct Node{
    int pos,dis;
    bool operator > (const Node &x) const {
        return x.dis<dis;
    }
};priority_queue<Node,vector<Node>,greater<Node> >Q;
bool Vis[N];int Dis[N];
int n,m,k,p;
inline void Dijkstra()
{
    Mem(Vis,0);Mem(Dis,127);    
    Q.push(Node{1,0});Dis[1]=0;
    while(!Q.empty())
    {
        int top=Q.top().pos;int dis=Q.top().dis;Q.pop();
        if(Vis[top]) continue;
        Vis[top]=1;
        for(int i=Head[top];i;i=Edge[i].nxt)
        {
            int arr=Edge[i].v;
            if(Edge[i].w+dis<Dis[arr])
            {
                Dis[arr]=Edge[i].w+dis;
                Q.push(Node{arr,Dis[arr]}); 
            } 
        }
    }
}
int F[N][52];bool Done[N][52];
int Dfs(int pos,int l)
{
    if(l>k or l<0) return 0;
    if(Done[pos][l]) {Done[pos][l]=0;return -1;}
    if(F[pos][l]!=-1) return F[pos][l];
    Done[pos][l]=1;
    int ans=0;
    for(int i=Pre[pos];i;i=Reverse[i].nxt)
    {
        int arr=Reverse[i].v;
        int tmp=Dfs(arr,l-Reverse[i].w-Dis[arr]+Dis[pos]);
        if(tmp==-1)
        {
            Done[pos][l]=0;
            return -1;
        }
        ans+=tmp;
        ans%=p;
    }
    Done[pos][l]=0;
    if(pos==1 and l==0)
    {
        F[pos][l]=1;
        return 1;
    }
    return F[pos][l]=ans;
}
signed main()
{
    #ifndef ONLINE_JUDGE
        freopen("data.in","r",stdin);
    #endif
    int T=gi();
    while(T--)
    {
        cnt=cnt1=0;Mem(Head,0);Mem(Pre,0);
        in4(n,m,k,p);
        for(int i=1;i<=m;++i)
        {
            int u,v,w;in3(u,v,w);
            Add(u,v,w);Link(v,u,w);
        }
        Dijkstra();
        // for(int i=1;i<=n;++i)
            // write(Dis[i]);
        // return 0;    
        Mem(F,-1);
        int ans=0;int flag=0;
        for(int i=0;i<=k;++i)
        {
            int tmp=Dfs(n,i);
            if(tmp==-1)
            {
                puts("-1");
                flag=1;
                break;
            }
            ans+=tmp;
            ans%=p;
        }
        if(!flag)
        {
            write(ans);line();
        }
    }
}

以上是关于逛公园的主要内容,如果未能解决你的问题,请参考以下文章

Noip2017 逛公园

P3953 逛公园

[NOIP2017]逛公园

洛谷3953:逛公园——题解

Luogu P3953 逛公园(最短路+记忆化搜索)

TYVJ1427 小白逛公园