[关闭]
@ysner 2018-08-20T00:45:49.000000Z 字数 2260 阅读 1990

[POI2006]PRO-Professor Szu

拓扑排序 图论


题面

个别墅以及一个主建筑楼,有条无向边,从每个别墅都有很多种不同方式走到主建筑楼。
其中不同的定义是:每条边可以走多次,如果走边的顺序有一条不同即称两方式不同。
询问经过边数最多的不同方式是多少,以及有多少个别墅有这么多方式,按照顺序输出别墅编号。

解析

显然如果一栋别墅在环内(包括自环),第一个答案就是无限。
所以在统计完答案无限的别墅后,必须缩点,才能统计其他别墅的答案。
此时判断答案无限的标准:

接下来设为走到点的方式数。
则边界为
那么转移方程式为
显然为了消除后效性需要拓扑排序。
于是从主建筑楼开始拓扑排序即可。

值得注意的是:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<queue>
  8. #define re register
  9. #define il inline
  10. #define ll long long
  11. #define max(a,b) ((a)>(b)?(a):(b))
  12. #define min(a,b) ((a)<(b)?(a):(b))
  13. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  14. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  15. using namespace std;
  16. const int mod=1e9+7,N=1e6+100,M=36501;
  17. struct Edge{int to,nxt;}e[N<<1],e1[N<<1];
  18. int n,m,h[N],cnt,dfn[N],low[N],sta[N],top,tim,scc,bl[N],in[N],f[N],sz[N],ans;
  19. bool gg[N],vis[N],gu[N];
  20. queue<int>Q;
  21. il void add(re int u,re int v){e[++cnt]=(Edge){v,h[u]};h[u]=cnt;}
  22. il ll gi()
  23. {
  24. re ll x=0,t=1;
  25. re char ch=getchar();
  26. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  27. if(ch=='-') t=-1,ch=getchar();
  28. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  29. return x*t;
  30. }
  31. il void tarjan(re int u)
  32. {
  33. dfn[u]=low[u]=++tim;vis[u]=1;sta[++top]=u;
  34. re int v;
  35. for(re int i=h[u];i+1;i=e[i].nxt)
  36. {
  37. v=e[i].to;
  38. if(u==v) gg[v]=1;
  39. if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
  40. else if(vis[v]) low[u]=min(low[u],dfn[v]);
  41. }
  42. if(low[u]==dfn[u])
  43. {
  44. ++scc;
  45. do{v=sta[top];bl[v]=scc;sz[scc]++;vis[v]=0;top--;}while(u^v);
  46. }
  47. }
  48. il void Topo()
  49. {
  50. f[bl[n]]=1;if(gu[bl[n]]||sz[bl[n]]>1) f[bl[n]]=M;
  51. fp(i,1,n) if(!in[i]) Q.push(i);
  52. while(!Q.empty())
  53. {
  54. re int u=Q.front();Q.pop();
  55. for(re int i=h[u];i+1;i=e[i].nxt)
  56. {
  57. re int v=e[i].to;--in[v];
  58. f[v]=min(f[v]+f[u],M);
  59. if(!in[v])
  60. {
  61. if((gu[v]||sz[v]>1)&&f[v]) f[v]=M;
  62. Q.push(v);
  63. }
  64. }
  65. }
  66. }
  67. int main()
  68. {
  69. memset(h,-1,sizeof(h));
  70. n=gi()+1;m=gi();
  71. fp(i,1,m)
  72. {
  73. re int u=gi(),v=gi();
  74. add(v,u);
  75. }
  76. fp(i,1,n) if(!dfn[i]) tarjan(i);top=0;
  77. fp(u,1,n)
  78. for(re int i=h[u];i+1;i=e[i].nxt)
  79. {
  80. re int v=e[i].to;
  81. if(bl[u]^bl[v]) e1[++top]=(Edge){bl[u],bl[v]};
  82. }
  83. memset(h,-1,sizeof(h));cnt=0;
  84. fp(i,1,top) add(e1[i].to,e1[i].nxt),++in[e1[i].nxt];
  85. fp(i,1,n) if(gg[i]) gu[bl[i]]=1;
  86. Topo();top=0;
  87. fp(i,1,n-1) ans=max(ans,f[bl[i]]);
  88. fp(i,1,n-1) if(f[bl[i]]==ans) sta[++top]=i;
  89. if(ans==M) puts("zawsze");else printf("%d\n",ans);
  90. printf("%d\n",top);
  91. fp(i,1,top) printf("%d ",sta[i]);puts("");
  92. return 0;
  93. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注