NOIP2017洛谷P3953:逛公园(分层图最短路、dp、拓扑)
生活随笔
收集整理的這篇文章主要介紹了
NOIP2017洛谷P3953:逛公园(分层图最短路、dp、拓扑)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
解析
容易想到dp
先跑一遍最短路把每個點的dis求出來
設計dpu,xdp_{u,x}dpu,x?表示結點u多走了x的方案數
dp按照dis升序排列后,從前到后轉移即可
如果有0邊,求出只有0邊時的拓撲序,作為第二關鍵字進行排序
關于0環,第一篇題解的拓撲似乎是假的…
利用dfs和記搜就是真的了
但是不想改了
代碼
#include<bits/stdc++.h> using namespace std; #define ll long long #define il inline #define debug(a,b) fprintf(stderr,a,b) const int N=1e6+100; inline ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f; } int n,m,k,mod; #define pr pair<int,int> #define mkp make_pair struct graph{struct edge{int to,nxt,w;}p[N<<1];int fi[N],cnt;int dis[N],du[N];bool tag[N];int id[N];int tot;priority_queue<pr,vector<pr>,greater<pr> >pq;int vis[N];queue<int>q;void init(){tot=0;memset(fi,-1,sizeof(fi));cnt=-1;memset(tag,0,sizeof(tag));memset(vis,0,sizeof(vis));memset(du,0,sizeof(du));memset(dis,0x3f,sizeof(dis));}inline void addline(int x,int y,int w){//if(fi[x]>1e7)//fprintf(stderr,"%d %d %d %d\n",x,y,w,fi[x]);p[++cnt]=(edge){y,fi[x],w};fi[x]=cnt;if(w==0) du[y]++;return;}void dij(int x){pq.push(mkp(0,x));dis[x]=0;while(!pq.empty()){int now=pq.top().second;pq.pop();//fprintf(stderr,"now=%d\n",now);if(vis[now]) continue;vis[now]=1;for(int i=fi[now];~i;i=p[i].nxt){int to=p[i].to;if(dis[to]>dis[now]+p[i].w){dis[to]=dis[now]+p[i].w;//fprintf(stderr,"%d->%d %d\n",now,to,dis[to]);pq.push(mkp(dis[to],to));//fprintf(stderr," ok\n");}//fprintf(stderr,"nxt=%d\n",p[i].nxt);}//fprintf(stderr,"------end\n");}return;}void topu(){//fprintf(stderr,"ok\n");for(int i=1;i<=n;i++){if(!du[i]) q.push(i);}while(!q.empty()){int now=q.front();q.pop();tag[now]=1;id[now]=++tot;for(int i=fi[now];~i;i=p[i].nxt){int to=p[i].to;if(!p[i].w){--du[to];if(!du[to]){q.push(to);//fprintf(stderr,"%d\n",to);}}}}} }g1,g2;int dp[N][52]; int ans; int que[N]; bool cmp(int x,int y){if(g1.dis[x]!=g1.dis[y])return g1.dis[x]<g1.dis[y];else return g1.id[x]<g1.id[y]; } int main(){ #ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout); #endifint T=read();while(T--){g1.init();g2.init();n=read();m=read();k=read();mod=read();for(int i=1;i<=m;i++){int x=read(),y=read(),w=read();g1.addline(x,y,w);g2.addline(y,x,w);}g1.dij(1);g2.dij(n);g1.topu();g2.topu();int flag=0;for(int i=1;i<=n;i++){if(g1.tag[i]||g2.tag[i]) continue;if(g1.dis[i]+g2.dis[i]<=g1.dis[n]+k){flag=1;break;}}if(flag){printf("-1\n");continue;}for(int i=1;i<=n;i++) que[i]=i;sort(que+1,que+1+n,cmp);//for(int i=1;i<=n;i++) printf("%d(%d) ",que[i],g1.dis[que[i]]);//putchar('\n');memset(dp,0,sizeof(dp));int ans=0;dp[1][0]=1;for(int w=0;w<=k;w++){for(int pp=1;pp<=n;pp++){int now=que[pp];if(dp[now][w]==0) continue;for(int i=g1.fi[now];~i;i=g1.p[i].nxt){int to=g1.p[i].to;int o=w+g1.p[i].w+g1.dis[now]-g1.dis[to];if(o>k) continue;(dp[to][o]+=dp[now][w])%=mod;}}(ans+=dp[n][w])%=mod;}printf("%d\n",ans);}return 0; } /**/ 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的NOIP2017洛谷P3953:逛公园(分层图最短路、dp、拓扑)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 消息称特斯拉将于11月9日上调Model
- 下一篇: NOIP2016洛谷P1600:天天爱跑