【牛客小白月赛21】NC201607 DDoS 题目链接
明明是道水题,为什么如此fake。。qwq
题目描述越看越糊涂,大致意思就是有一个拓扑图(有向无环图),1号点可以在任意时间发送一个定向数据包到n号点(即路径可以你自己规定,到达n号点的所用时间为路径上的边权和),但n号点只要在某一时间收到数据包后就不会再收后面的数据包了。问最优策略下能够收到多少份数据包,即求最多有多少个数据包同时到达n号点。
跟着题意绕来绕去,看了别的题解才知道这几段话的重点:可以在任意时间发送!也就是说对于1到n的所有路径,尽管所用时间不同,可你完全可以通过调整他们的开始时间,使他们最后在同一时间到达。也就是说,所有路径都可以在同一时间到达!所有路径都是答案!
即求1到n的路径数,用拓扑排序或记忆化搜索都可,而且。。边权z没有任何作用(看别的题解说这里给了个奇怪的数据范围就是在暗示qwq)
方法一:记忆化搜索
#include<cstdio> using namespace std; #define max(a,b) (a>b ? a:b) const int p=20010905; inline int rd() { char ch=getchar(); int x=0; while(ch<'0' || ch>'9') ch=getchar(); while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return x; } struct edge { int v,h; } e[200005]; int h[100005],n,m,tot; int f[100005]; inline void add(int u,int v) { e[++tot]=(edge) { v,h[u] },h[u]=tot; } int dfs(int u) { if (f[u]!=0) return max(f[u],0);//记忆化搜索:f[u]为-1或正数直接返回 for (int i=h[u]; i; i=e[i].h) f[u]=(f[u]+dfs(e[i].v))%p; if (!f[u]) f[u]=-1;//如果走过但是答案为0就标记-1,防止下次再走 return max(f[u],0); } int main() { scanf("%d%d",&n,&m); for (int u,v,z; m; m--) u=rd(),v=rd(),z=rd(),add(u,v); f[n]=1; printf("%d",dfs(1)); }
方法二:拓扑排序
#include<cstdio> using namespace std; #define max(a,b) (a>b ? a:b) const int p=20010905; struct edge { int v,h; } e[200005]; int h[100005],r[100005],n,m,tot; int q[100005],head,tail,f[100005]; inline int rd() { char ch=getchar(); int x=0; while(ch<'0' || ch>'9') ch=getchar(); while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return x; } inline void add(int u,int v) { e[++tot]=(edge) { v,h[u] },h[u]=tot; } int main() { scanf("%d%d",&n,&m); for (int u,v,z; m; m--) u=rd(),v=rd(),z=rd(),r[v]++,add(u,v); f[1]=q[tail=1]=1; while(head<tail){ int u=q[++head]; for (int i=h[u],v; i; i=e[i].h){ v=e[i].v,r[v]--; if (!r[v]) q[++tail]=v; f[v]=(f[v]+f[u])%p; } } printf("%d",f[n]); }