[NOIP2017]逛公园(DP)
先spfa一遍处理出d[]数组,(从n开始bfs一遍标记可以达到n的点)
题意即,在走最短路的基础上,可以最多多走K长度的路径,
考虑DP,每次剩余可走的长度会因决策而改变,所以考虑dp[i][j]为当前在i号节点,剩余可多走长度为j的方案数
dp[u][j]可以从dp[v][e[i].w-(d[v]-d[u])]转移而来,(其中u->v,e[i].w-(d[v]-d[u])即为当前决策多走的路径))
再考虑有0边的情况,如果构成环就会无限方案数,只要在记忆化的时候特判一下-1即可
ps:对于一个dp[u][j]可能为0,初始化不能为0
Code
#include <cstdio> #include <algorithm> #include <queue> #include <cstring> #define N 100010 using namespace std; struct info{int to,nex,w;}e[N*2],re[N*2]; int T,n,m,k,mo,tot,head[N],d[N],rtot,rhead[N],dp[N][56]; bool ab[N]; bool vis[N][56]; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void Init(){ memset(vis,0,sizeof(vis)); memset(head,0,sizeof(head)); memset(rhead,0,sizeof(rhead)); memset(ab,0,sizeof(ab)); memset(dp,-1,sizeof(dp)); tot=rtot=0; } inline void Link(int u,int v,int w){ e[++tot].to=v,e[tot].w=w;e[tot].nex=head[u];head[u]=tot; } inline void rLink(int u,int v,int w){ re[++rtot].to=v,re[rtot].w=w;re[rtot].nex=rhead[u];rhead[u]=rtot; } namespace SPFA{ queue<int> q; bool vis[N]; void spfa(){ for(;!q.empty();q.pop()); memset(vis,0,sizeof(vis)); memset(d,127,sizeof(d)); d[1]=0,q.push(1); for(;!q.empty();){ int u=q.front();vis[u]=0,q.pop(); for(int i=head[u];i;i=e[i].nex){ int v=e[i].to; if(d[v]>d[u]+e[i].w){ d[v]=d[u]+e[i].w; if(!vis[v]) vis[v]=1,q.push(v); } } } memset(vis,0,sizeof(vis)); } void afps(){ for(;!q.empty();q.pop()); q.push(n),ab[n]=1; for(;!q.empty();){ int u=q.front();q.pop(); for(int i=rhead[u];i;i=re[i].nex){ int v=re[i].to; if(ab[v]) continue; ab[v]=1,q.push(v); } } } void work(){spfa(),afps();} } int DP(int u,int k){ if(k<0)return 0; int &tmp=dp[u][k]; if(vis[u][k]) return -2; if(tmp!=-1) return tmp; vis[u][k]=1; tmp=(u==n)?1:0; for(int i=head[u];i;i=e[i].nex){ int v=e[i].to; if(!ab[v]) continue; int x=DP(v,k-(e[i].w-(d[v]-d[u]))); if(x==-2) return -2; else (tmp+=x)%=mo; } vis[u][k]=0; return tmp; } int main(){ for(T=read();T--;){ Init(); n=read(),m=read(),k=read(),mo=read(); for(;m--;){ int u=read(),v=read(),w=read(); Link(u,v,w),rLink(v,u,w); } SPFA::work(); int Ans=DP(1,k); if(Ans==-2)puts("-1"); else printf("%d\n",Ans); } return 0; }