NOIP2017 Day1 T3 逛公園(spfa+dfs)
阿新 • • 發佈:2018-12-12
原來k≤50。。我還擔心開不下。。
設代表當前點在誤差小於等於k時到達終點的情況數量
首先求出n到每個點的最短路。然後dfs,每次如果dis[to]-dis[u]+edge[i].val≤k那麼就可以更新。如果搜過的點出現過那麼直接-1
最後返回dfs的值(也就是f[1][K])即可
#include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<queue> using namespace std; typedef long long ll; int T,n,m,K,p; struct node { int to; int nxt; int val; }edge[400005]; int head[100005]; int f[100005][52]; int used[100005]; int us[100005][52]; int dis[100005]; int cnt=1; void init() { memset(head,-1,sizeof(head)); memset(f,0,sizeof(f)); memset(us,0,sizeof(us)); cnt=1; } void add(int from,int to,int val) { edge[cnt].to=to; edge[cnt].val=val; edge[cnt].nxt=head[from]; head[from]=cnt++; } queue<int>M; void spfa() { memset(dis,0x3f,sizeof(dis)); memset(used,0,sizeof(used)); dis[n]=0; used[n]=1; M.push(n); while(!M.empty()) { int u=M.front();M.pop(); for(int i=head[u];i!=-1;i=edge[i].nxt) { if(i%2==1)continue; int to=edge[i].to; if(dis[to]>dis[u]+edge[i].val) { dis[to]=dis[u]+edge[i].val; if(used[to])continue; used[to]=1;M.push(to); } } used[u]=0; } } int dfs(int u,int k) { if(us[u][k])return -1; if(f[u][k])return f[u][k]; us[u][k]=1;f[u][k]=(u==n?1:0); for(int i=head[u];i!=-1;i=edge[i].nxt) { if(i%2==0)continue; int to=edge[i].to,w,op; if((w=(k-(dis[to]+edge[i].val-dis[u])))>=0) { if((op=dfs(to,w))==-1)return /*f[u][k]*/=-1; else f[u][k]+=op,f[u][k]%=p; } } return us[u][k]=0,f[u][k]; } int main() { scanf("%d",&T); while(T--) { init(); scanf("%d%d%d%d",&n,&m,&K,&p); for(int i=1;i<=m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } spfa();printf("%d\n",dfs(1,K)); } return 0; }