【題解】洛谷P3953[NOIP2017]逛公園 最短路+拓撲排序+計數類DP
阿新 • • 發佈:2018-12-14
學習了大佬題解。根據大佬的講解,把對應部分分的程式碼打到一起了。(有點臃腫)
#pragma GCC optimize(2) #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; typedef long long ll; const int N=1e5+10,M=2e5+10; #define re register int tot,t,n,m,k,p,hd[N],vis[N],hdn[N],totn,id[N],idx[N]; int cnt[N],f[N][55],ans,deg[N],hd0[N],tot0,q[N]; ll dis[N],disn[N]; inline int read() { int s=0,f=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+(ch^48),ch=getchar(); return s*f; } struct Edge{ int v,nx;ll w; }e[M],en[M]; struct node{ int u;ll w; node(){} node(int _u,ll _w):u(_u),w(_w){} bool operator <(const node&rhs)const{ return w>rhs.w;} }; namespace pts30{ void add(int u,int v,ll w) { e[tot].v=v; e[tot].nx=hd[u]; e[tot].w=w; hd[u]=tot++; } void dijkstra() { memset(dis,0x7f,sizeof(dis));memset(vis,0,sizeof(vis)); priority_queue<node>q;dis[1]=0;q.push(node(1,0));cnt[1]=1; while(q.size()) { int u=q.top().u;q.pop();vis[u]=0; for(int i=hd[u];~i;i=e[i].nx) { int v=e[i].v; if(dis[v]>dis[u]+e[i].w) { dis[v]=dis[u]+e[i].w;cnt[v]=cnt[u]; if(!vis[v])vis[v]=1,q.push(node(v,dis[v])); } else if(dis[v]==dis[u]+e[i].w) { cnt[v]+=cnt[u]; if(cnt[v]>=p)cnt[v]-=p; } } } printf("%d\n",cnt[n]%p); } void solve() { using namespace pts30; t=read(); while(t--) { memset(hd,-1,sizeof(hd));tot=0; n=read();m=read();k=read();p=read(); int u,v;ll w; for(int i=1;i<=m;i++) u=read(),v=read(),w=read(),add(u,v,w); dijkstra(); } } } namespace pts70{ inline void add(int u,int v,ll w) { e[tot].v=v; e[tot].nx=hd[u]; e[tot].w=w; hd[u]=tot++; } bool cmp(const int &a,const int &b) { return dis[a]<dis[b]; } void dijkstra() { memset(dis,0x7f,sizeof(dis));memset(vis,0,sizeof(vis)); priority_queue<node>q;dis[1]=0;q.push(node(1,0)); while(q.size()) { int u=q.top().u;q.pop();vis[u]=0; for(int i=hd[u];~i;i=e[i].nx) { int v=e[i].v; if(dis[v]>dis[u]+e[i].w) { dis[v]=dis[u]+e[i].w; if(!vis[v])vis[v]=1,q.push(node(v,dis[v])); } } } } void solve() { using namespace pts70; t=read(); while(t--) { memset(hd,-1,sizeof(hd));tot=0; memset(hdn,-1,sizeof(hdn));totn=0; memset(f,0,sizeof(f));ans=0; n=read();m=read();k=read();p=read(); int u,v;ll w; for(int i=1;i<=m;i++) u=read(),v=read(),w=read(),add(u,v,w); dijkstra(); for(int i=1;i<=n;i++)id[i]=i; sort(id+1,id+n+1,pts70::cmp); f[1][0]=1; for(int j=0;j<=k;j++) for(int i=1;i<=n;i++) { int u=id[i]; for(int o=hd[u];~o;o=e[o].nx) { int v=e[o].v;ll w=e[o].w; if(dis[u]+j+w-dis[v]<=k) { f[v][dis[u]+j+w-dis[v]]+=f[u][j]; if(f[v][dis[u]+j+w-dis[v]]>=p)f[v][dis[u]+j+w-dis[v]]-=p; } } } for(int j=0;j<=k;j++) { ans+=f[n][j];if(ans>=p)ans-=p; } printf("%d\n",ans); } } } namespace AC{ struct Edge0{ int v,nx; }e0[M]; inline void add(int u,int v,ll w) { e[tot].v=v; e[tot].nx=hd[u]; e[tot].w=w; hd[u]=tot++; } inline void addn(int u,int v,ll w) { en[totn].v=v; en[totn].nx=hdn[u]; en[totn].w=w; hdn[u]=totn++; } inline void add0(int u,int v) { e0[tot0].v=v; e0[tot0].nx=hd0[u]; hd0[u]=tot0++; } inline void dijkstran() { memset(disn,0x7f,sizeof(disn));memset(vis,0,sizeof(vis)); priority_queue<node>q;disn[1]=0;q.push(node(1,0)); while(q.size()) { re int u=q.top().u;q.pop();vis[u]=0; for(re int i=hdn[u];~i;i=en[i].nx) { re int v=en[i].v; if(disn[v]>disn[u]+en[i].w) { disn[v]=disn[u]+en[i].w; if(!vis[v])vis[v]=1,q.push(node(v,disn[v])); } } } } inline void dijkstra() { memset(dis,0x7f,sizeof(dis));memset(vis,0,sizeof(vis)); priority_queue<node>q;dis[1]=0;q.push(node(1,0)); while(q.size()) { re int u=q.top().u;q.pop();vis[u]=0; for(re int i=hd[u];~i;i=e[i].nx) { re int v=e[i].v; if(dis[v]>dis[u]+e[i].w) { dis[v]=dis[u]+e[i].w; if(!vis[v])vis[v]=1,q.push(node(v,dis[v])); } } } } bool toposort() { re int h=1,t=0; for(re int i=1;i<=n;i++) if(!deg[i])q[++t]=i; while(h<=t) { re int u=q[h++]; for(re int i=hd0[u];~i;i=e0[i].nx) { re int v=e0[i].v; if(--deg[v]==0)q[++t]=v; } } for(re int i=1;i<=n;i++)id[q[i]]=i; for(re int i=1;i<=n;i++) if(deg[i]&&dis[i]+disn[i]-dis[n]<=k)return true; return false; } inline bool cmp(const int &a,const int &b) { return dis[a]<dis[b]||(dis[a]==dis[b]&&id[a]<id[b]); } inline void solve() { using namespace AC; t=read(); while(t--) { memset(hd,-1,sizeof(hd));tot=0; memset(hdn,-1,sizeof(hdn));totn=0; memset(hd0,-1,sizeof(hd0));tot0=0; memset(deg,0,sizeof(deg));memset(f,0,sizeof(f));ans=0; n=read();m=read();k=read();p=read(); int u,v,w; for(re int i=1;i<=m;i++) { u=read();v=read();w=read();add(u,v,w);addn(v,u,w); if(!w)add0(u,v),deg[v]++; } dijkstra();dijkstran(); if(toposort()){puts("-1");continue;} f[1][0]=1; for(re int i=1;i<=n;i++)idx[i]=i;sort(idx+1,idx+n+1,cmp); for(re int j=0;j<=k;j++) for(re int i=1;i<=n;i++) { re int u=idx[i]; for(re int o=hd[u];~o;o=e[o].nx) { re int v=e[o].v;ll w=e[o].w; if(dis[u]+w+j-dis[v]<=k) { f[v][dis[u]+w+j-dis[v]]+=f[u][j]; if(f[v][dis[u]+w+j-dis[v]]>=p)f[v][dis[u]+w+j-dis[v]]-=p; } } } for(re int i=0;i<=k;i++) { ans+=f[n][i]; if(ans>=p)ans-=p; } printf("%d\n",ans); } } } int main() { //freopen("in.txt","r",stdin); //pts30::solve(); //pts70::solve(); AC::solve(); return 0; }
總結
首先看到路徑數,想能不能DP轉移,然後通過求出的最短路按照拓撲序進行轉移,還得判斷0環。