P2272 [ZJOI2007]最大半连通子图

萌新初学Tarjan,在《信息学奥赛一本通-提高篇》中看到这题,看到题解不多,便想发布一篇较为清新简洁的题解。——第5道紫题

题目大意:

定义最大半连通图:对于图中任意两点u,v,存在一条u到v的有向路径 或者 从v到u的有向路径。求一个图中不同的最大半连通子图的数目。

看到题面时大家很容易想到,如果两点互相可以到达,那么它们必是半连通图,所以考虑先Tarjan缩点(P3387 【模板】缩点(Tarjan缩点+DAGdp)

接着去除重边重新建图,你会发现,在这个有向无环图(DAG)中,半连通子图都是一条链(可以举反例试试,这条链不可能有分支,否则将有两点无法抵达另一方)

于是,G的最大半连通子图拥有的节点数K就是最长链长度,不同的最大半连通子图的数目就是最长链个数。

信息学一本通:最长链可以直接用拓扑排序(topo),最长链个数用一个类似DP的方法,用f【i】表示以 i 为终点的方案数,那么f【i】就等于满足距离为起点到 i 的临时最短距离的点的 f 的和。然后查找距离等于最长链的点,答案为它们的方案数之和

其他题解中已经给出了拓扑的算法,我借鉴大佬的程序用的是搜索,先一直搜到终点再回来更新答案。由于数据范围#7一直RE,后来改为const int N=1e5+5,M=2e6+5;终于AC。。qwq高性能。。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. const int N=1e5+5,M=2e6+5;
  6. bool f[N];
  7. //f 在搜索中判断是否走过
  8. int n,m,mod,now,d[N],a[N],ans,maxans,ch[N];
  9. //d指从u到终点的最长链距离,a指最长链点数,ch指出度
  10. int h[N],u[M],v[M],r[N],nu[M],cnt;
  11. //h是链式前向星的建边head,u,v保存初始读入的边左右两点,nu存初始时边的编号,r是入度
  12. int top,co,dfn[N],low[N],c[N],s[N],st[N];
  13. //dfn,low,st用于Tarjan,c表所在强连通分量编号,s指所在强连通分量点数
  14. struct edge {
  15. int h,to;
  16. } e[M];
  17. #define rint register int
  18. #define min(a,b) (a<b? a:b)
  19. #define max(a,b) (a>b? a:b)
  20. inline bool cmp(int a,int b) {
  21. return u[a]<u[b] || (u[a]==u[b] && v[a]<v[b]);
  22. }//将边排序,方便重新建图
  23. inline void add(int u,int v) {
  24. e[++cnt].h=h[u],h[u]=cnt,e[cnt].to=v;
  25. }
  26. inline int read() {
  27. int w=1,ans=0;
  28. char ch=getchar();
  29. while(ch>'9'||ch<'0') if (ch=='-') w=-1,ch=getchar();
  30. while(ch<='9'&& ch>='0') ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
  31. return ans*w;
  32. }
  33. inline void Tarjan(int u) {
  34. dfn[u]=low[u]=++now;
  35. st[++top]=u;
  36. for (rint i=h[u]; i; i=e[i].h) {
  37. int v=e[i].to;
  38. if (!dfn[v])
  39. Tarjan(v),low[u]=min(low[u],low[v]);
  40. else if (!c[v])
  41. low[u]=min(low[u],dfn[v]);
  42. }
  43. if (low[u]==dfn[u]) {
  44. c[u]=++co,s[co]++;
  45. while(st[top]!=u)
  46. s[co]++,c[st[top]]=co,top--;
  47. top--;
  48. }
  49. }//标准缩点
  50. inline void dfs(int u) {
  51. f[u]=1;
  52. if (!ch[u]) {//如果没有出度,即到头了
  53. d[u]=s[u],a[u]=1;//距离为点数,以u为起点方案为1
  54. maxans=max(maxans,d[u]);//更新最长链距离
  55. return;
  56. }
  57. for (rint i=h[u]; i; i=e[i].h) {
  58. int v=e[i].to;
  59. if (!f[v]) dfs(v);//继续搜索链的后面
  60. if (d[v]+s[u]>d[u])//若以u为起点的链距离可以更长
  61. d[u]=d[v]+s[u],a[u]=a[v]%mod;//更新
  62. else if (d[u]==d[v]+s[u])//若最长链距离相同
  63. a[u]=(a[u]+a[v])%mod;//加上方案数
  64. maxans=max(maxans,d[u]);
  65. }
  66. }
  67. int main() {
  68. n=read(),m=read(),mod=read();
  69. for (rint i=1; i<=m; i++) u[i]=read(),v[i]=read(),add(u[i],v[i]);
  70. for (rint i=1; i<=n; i++) if (!dfn[i]) Tarjan(i);
  71. cnt=0;
  72. memset(h,0,sizeof h);
  73. memset(e,0,sizeof e);
  74. for (rint i=1; i<=m; i++)
  75. nu[i]=i,u[i]=c[u[i]],v[i]=c[v[i]];
  76. sort(nu+1,nu+m+1,cmp);//按u,v排序边
  77. for (rint i=1; i<=m; i++)
  78. {
  79. int num=nu[i];
  80. if (u[num]!=v[num] && (u[num]!=u[nu[i-1]] || v[num]!=v[nu[i-1]]))//若此边不是自环,且与上一条边不同(去除重边)
  81. ++ch[u[num]],++r[v[num]],add(u[num],v[num]);}
  82. //出度入度加1,加边
  83. for (rint i=1; i<=co; i++) if (!r[i] && !f[i]) dfs(i);//入度为0且未搜索过
  84. for (rint i=1; i<=co; i++) if (d[i]==maxans) ans=(ans+a[i])%mod;//统计答案
  85. printf("%d\n%d\n",maxans,ans);
  86. }

题解 P2272 【[ZJOI2007]最大半连通子图】的更多相关文章

  1. 洛谷 P2272 [ZJOI2007]最大半连通子图 解题报告

    P2272 [ZJOI2007]最大半连通子图 题目描述 一个有向图\(G=(V,E)\)称为半连通的\((Semi-Connected)\),如果满足:\(\forall u,v \in V\),满 ...

  2. Luogu P2272 [ZJOI2007]最大半连通子图(Tarjan+dp)

    P2272 [ZJOI2007]最大半连通子图 题意 题目描述 一个有向图\(G=(V,E)\)称为半连通的\((Semi-Connected)\),如果满足:\(\forall u,v\in V\) ...

  3. luogu P2272 [ZJOI2007]最大半连通子图

    题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若 ...

  4. P2272 [ZJOI2007]最大半连通子图 tarjan+DP

    思路:$tarjan+DP$ 提交:1次 题解:首先对于一个强连通分量一定是一个半连通分量,并且形成的半连通分量的大小一定是它的$size$,所以我们先缩点. 这样,我们相当于要在新的$DAG$上找一 ...

  5. P2272 [ZJOI2007]最大半连通子图

    思路 tarjan的题目 注意是要选出一个点集而不是边集 第一问就是缩点之后最长链,第二问就是有多少个最长链,注意缩点后连边要去重(不然一个链的方案可能会被统计多次) 代码 #include < ...

  6. BZOJ 1093 [ZJOI2007]最大半连通子图

    1093: [ZJOI2007]最大半连通子图 Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 1986  Solved: 802[Submit][St ...

  7. BZOJ 1093 [ZJOI2007] 最大半连通子图(强联通缩点+DP)

    题目大意 题目是图片形式的,就简要说下题意算了 一个有向图 G=(V, E) 称为半连通的(Semi-Connected),如果满足图中任意两点 u v,存在一条从 u 到 v 的路径或者从 v 到 ...

  8. bzoj 1093 [ZJOI2007]最大半连通子图(scc+DP)

    1093: [ZJOI2007]最大半连通子图 Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 2286  Solved: 897[Submit][St ...

  9. BZOJ 1093: [ZJOI2007]最大半连通子图( tarjan + dp )

    WA了好多次... 先tarjan缩点, 然后题意就是求DAG上的一条最长链. dp(u) = max{dp(v)} + totu, edge(u,v)存在. totu是scc(u)的结点数. 其实就 ...

随机推荐

  1. Java Date Calendar DateFormat Details

    From https://www.ntu.edu.sg/home/ehchua/programming/java/DateTimeCalendar.html Date and Time - Creat ...

  2. Windows Vista 的历史地位

    Windows Vista,这是一个不那么如雷贯耳的Windows名字,很多人甚至从来没有体验过这个操作系统.但是,Windows Vista刚刚推出时候所引起的话题性,恐怕是其后的Win7也难以与之 ...

  3. [转载] ASP.NET MVC (一)——深入理解ASP.NET MVC

    个人认为写得比较透彻得Asp.net mvc 文章,所以转载过来,原文链接在最后: ASP.NET vs MVC vs WebForms 许多ASP.NET开发人员开始接触MVC认为MVC与ASP.N ...

  4. The Portable Executable File Format from Top to Bottom(每个结构体都非常清楚)

    The Portable Executable File Format from Top to Bottom Randy KathMicrosoft Developer Network Technol ...

  5. Codility---Nesting

    Task description A string S consisting of N characters is called properly nested if: S is empty; S h ...

  6. python网络爬虫(10)分布式爬虫爬取静态数据

    目的意义 爬虫应该能够快速高效的完成数据爬取和分析任务.使用多个进程协同完成一个任务,提高了数据爬取的效率. 以百度百科的一条为起点,抓取百度百科2000左右词条数据. 说明 参阅模仿了:https: ...

  7. 我所理解的Vue——学习心得体会1(Vue对象)

    初学Vue,总结如下: 1.首先要区分html的dom和js的dom 2.html的dom是View的范畴,js的dom是Model的范畴. 3.vue这库就是创建了伟大的new Vue()对象,把h ...

  8. Django之用户认证auth模块使用

    Auth认证模块 执行数据库迁移的那两条命令时,即使我们没有建表,django是不是也会创建好多张表?我们创建之后去看一下里面的一个叫auth_user表,既然是表,那肯定应该有对应的操作改表的方法 ...

  9. spring boot 2.x 系列 —— spring boot 实现分布式 session

    文章目录 一.项目结构 二.分布式session的配置 2.1 引入依赖 2.2 Redis配置 2.3 启动类上添加@EnableRedisHttpSession 注解开启 spring-sessi ...

  10. Codeforces 776D:The Door Problem(DFS染色)

    http://codeforces.com/problemset/problem/776/D 题意:有n个门,m个开关,每个门有一个当前的状态(0表示关闭,1表示打开),每个开关控制k个门,但是每个门 ...