P3524 最大半连通子图
时间: 3000ms / 空间: 165536KiB / Java类名: Main

描述

输入格式

第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述。接下来M行,每行两个正整数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。

输出格式

应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.

测试样例1

输入

6 6 20070603 
1 2 
2 1 
1 3 
2 4 
5 6 
6 4

输出


3

备注

对于20%的数据, N ≤18; 
对于60%的数据, N ≤10000; 
对于100%的数据, N ≤100000, M ≤1000000; 
对于100%的数据, X ≤10^8。

最开始的时候没有考虑到有环的时候,他可以连续跑,就没有进行缩点,结果就只能A第二个点

后来wa掉以后发现如果有环的时候不进行缩点的话,由于两个不相同的半联通子图满足他们至少有一个点不相同,而如果按照我上面的思路的话我们下面的图跑出来会是3个半连通子图,而且最长的链会是3而正确结果是2 1

这样的话我们就必须缩点了,我们先tarjan求强连通分量,然后在进行缩点,对跑出来的新图进行拓扑排序,然后在拓扑排序里面加dp。

  1. 仔细考虑了一下,好像我dfs然后在加暴力枚举根本就不可行、、、
  2.  
  3. #include<queue>
  4. #include<cstdio>
  5. #include<cstring>
  6. #include<cstdlib>
  7. #include<iostream>
  8. #include<algorithm>
  9. #define N 1100000
  10. using namespace std;
  11. bool vis[N],vist[N];
  12. int n,m,x,y,s,tot,tat,mod,ans1,ans2,top,tim;
  13. int in[N],ss[N],dfn[N],low[N],head[N],head1[N],ans[N],sum[N],stack[N],belong[N];
  14. int read()
  15. {
  16. ,f=; char ch=getchar();
  17. ; ch=getchar();}
  18. +ch-'; ch=getchar();}
  19. return x*f;
  20. }
  21. struct Edge
  22. {
  23. int to,from,next;
  24. }edge[N],edge1[N];
  25. int add(int x,int y)
  26. {
  27. tot++;
  28. edge[tot].to=y;
  29. edge[tot].from=x;
  30. edge[tot].next=head[x];
  31. head[x]=tot;
  32. }
  33. int add1(int x,int y)
  34. {
  35. tat++;
  36. edge1[tat].to=y;
  37. edge1[tat].from=x;
  38. edge1[tat].next=head1[x];
  39. head1[x]=tat;
  40. }
  41. int tarjan(int now)
  42. {
  43. dfn[now]=low[now]=++tim;
  44. vis[now]=true; stack[++top]=now;
  45. for(int i=head[now];i;i=edge[i].next)
  46. {
  47. int t=edge[i].to;
  48. if(vis[t]) low[now]=min(low[now],dfn[t]);
  49. else if(!dfn[t]) tarjan(t),low[now]=min(low[now],low[t]);
  50. }
  51. if(low[now]==dfn[now])
  52. {
  53. s++,belong[now]=s,ss[s]++;
  54. for(;stack[top]!=now;top--)
  55. belong[stack[top]]=s,vis[stack[top]]=false,ss[s]++;
  56. vis[now]=false,top--;
  57. }
  58. }
  59. int shink_point()
  60. {
  61. ;i<=n;i++)
  62. for(int j=head[i];j;j=edge[j].next)
  63. if(belong[i]!=belong[edge[j].to])
  64. add1(belong[i],belong[edge[j].to]);
  65. }
  66. int dfs(int x)
  67. {
  68. vist[x]=true;
  69. for(int i=head1[x];i;i=edge1[i].next)
  70. {
  71. int t=edge1[i].to;
  72. if(!vist[t]) dfs(t);
  73. ;
  74. }
  75. vist[x]=false;
  76. }
  77. int tpsort(int s,int * in)
  78. {
  79. memset(sum,,sizeof(sum));
  80. queue<int>q;
  81. q.push(s);sum[s]=ss[s];
  82. while(!q.empty())
  83. {
  84. int x=q.front();q.pop();
  85. for(int i=head1[x];i;i=edge1[i].next)
  86. {
  87. int t=edge1[i].to;
  88. ) continue;
  89. in[t]--;
  90. ) q.push(t);
  91. sum[t]=max(sum[t],sum[x]+ss[t]);
  92. }
  93. }
  94. }
  95. int main()
  96. {
  97. n=read(),m=read();mod=read();
  98. ;i<=m;i++)
  99. x=read(),y=read(),add(x,y);
  100. ;i<=n;i++)
  101. if(!dfn[i]) tarjan(i);
  102. shink_point();
  103. memset(vis,,sizeof(vis));
  104. ;i<=n;i++)
  105. {
  106. if(vis[belong[i]]) continue;
  107. vis[belong[i]]=true;
  108. memset(,sizeof(in));
  109. dfs(belong[i]);tpsort(belong[i],in);
  110. sort(sum+,sum++n);
  111. ans[i]=sum[n];
  112. ans1=max(ans1,ans[i]);
  113. }
  114. ;i<=s;i++)
  115. if(ans[i]==ans1) ans2++;
  116. printf("%d\n%d\n",ans1,ans2);
  117. ;
  118. }

20分tle代码

怎么跑??

我们先考虑一个问题:在tarjan缩完点以后我们在建新图的时候一定会建出重边来,但是我们要进行拓扑排序的话就不可以有重边,所以我们要在进行缩点后建图的时候一定要判断这条边是否是重边,我们用一个map数组来判断。

然后我们在拓扑排序里面跑dp,为什么要用拓扑排序??因为通拓扑排序可以很容易的找出最长链。

怎么dp??     我们在第一部找出它的最大半联通子图的时候,其实找的就是最长链,我们把它最长链里面的权值进行合并就行。我们用一个ans记录到达当前点的最大权值,用v表示当前节点,用x表示与v连通那个点。由于我们有好几条路径可以到达v点,而我们要统计的是最大的半连通子图的大小,所以我们在对当前点更新的时候则为ans[v]=max(ans[v],ans[x])为什么是这样??因为我们对于每一条链的ans[x]是一直在更新的。这样我们就可以把最大的半联通子图统计出来。ans1=max(ans1,ans[i]).其次我们还要统计方案数。我们用数组dp记录到当前点的方案数,用数组deep记录到当前点的子图的大小, 然后我们判断这个点的deep值是否等于他父节点的deep值(暂且这样叫吧、、)如果相等的话就说明出现了另一种方案数,那么dp[t]=dp[t]+dp[x](加法原理其内容是:做一件事情,完成它有N类方式,第一类方式有M1种方法,第二类方式有M2种方法,……,第N类方式有M(N)种方法,那么完成这件事情共有M1+M2+……+M(N)种方法。)如果当前点的deep小与其父节点的deep那么我们对其dp进行修改,dp[t]=dp[x],deep[t]=deep[x]

  1. #include<map>
  2. #include<queue>
  3. #include<cstdio>
  4. #include<cstring>
  5. #include<cstdlib>
  6. #include<iostream>
  7. #include<algorithm>
  8. #define N 110000
  9. using namespace std;
  10. bool vis[N],vist[N];
  11. int n,m,x,y,s,tot,tat,mod,ans1,ans2,top,tim;
  12. ],head1[],ans[N],sum[N],stack[N],belong[N];
  13. int read()
  14. {
  15. ,f=; char ch=getchar();
  16. ; ch=getchar();}
  17. +ch-'; ch=getchar();}
  18. return x*f;
  19. }
  20. struct Edge
  21. {
  22. int to,from,next;
  23. }edge[],edge1[];
  24. int add(int x,int y)
  25. {
  26. tot++;
  27. edge[tot].to=y;
  28. edge[tot].from=x;
  29. edge[tot].next=head[x];
  30. head[x]=tot;
  31. }
  32. int add1(int x,int y)
  33. {
  34. tat++;
  35. edge1[tat].to=y;
  36. edge1[tat].from=x;
  37. edge1[tat].next=head1[x];
  38. head1[x]=tat;
  39. }
  40. int tarjan(int now)
  41. {
  42. dfn[now]=low[now]=++tim;
  43. vis[now]=true; stack[++top]=now;
  44. for(int i=head[now];i;i=edge[i].next)
  45. {
  46. int t=edge[i].to;
  47. if(vis[t]) low[now]=min(low[now],dfn[t]);
  48. else if(!dfn[t]) tarjan(t),low[now]=min(low[now],low[t]);
  49. }
  50. if(low[now]==dfn[now])
  51. {
  52. s++,belong[now]=s,sum[s]++;
  53. for(;stack[top]!=now;top--)
  54. belong[stack[top]]=s,vis[stack[top]]=false,sum[s]++;
  55. vis[now]=false,top--;
  56. }
  57. }
  58. map<int,int>ma[N];
  59. int shink_point()
  60. {
  61. ;i<=n;i++)
  62. for(int j=head[i];j;j=edge[j].next)
  63. if(belong[i]!=belong[edge[j].to])
  64. )
  65. {
  66. add1(belong[i],belong[edge[j].to]);
  67. in[belong[edge[j].to]]++;
  68. }
  69. }
  70. int tpsort()
  71. {
  72. queue<int>q;
  73. ;i<=s;i++)
  74. ;
  75. while(!q.empty())
  76. {
  77. int x=q.front();q.pop();ans[x]+=sum[x],deep[x]+=sum[x];
  78. for(int i=head1[x];i;i=edge1[i].next)
  79. {
  80. int t=edge1[i].to;
  81. in[t]--;
  82. if(!in[t]) q.push(t);
  83. ans[t]=max(ans[t],ans[x]);
  84. if(deep[t]==deep[x])
  85. dp[t]=(dp[t]+dp[x])%mod;
  86. else if(deep[t]<deep[x])
  87. dp[t]=dp[x],deep[t]=deep[x];
  88. }
  89. }
  90. ;i<=n;i++) ans1=max(ans1,ans[i]);
  91. ;i<=n;i++)
  92. if(ans[i]==ans1) ans2=(ans2+dp[i])%mod;
  93. }
  94. int main()
  95. {
  96. n=read(),m=read();mod=read();
  97. ;i<=m;i++)
  98. x=read(),y=read(),add(x,y);
  99. ;i<=n;i++)
  100. if(!dfn[i]) tarjan(i);
  101. shink_point(); tpsort();
  102. printf("%d\n%d\n",ans1,ans2);
  103. ;
  104. }

tyvj——P3524 最大半连通子图的更多相关文章

  1. 最大半连通子图 bzoj 1093

    最大半连通子图 (1.5s 128MB) semi [问题描述] 一个有向图G = (V,E)称为半连通的(Semi-Connected),如果满足:∀ u, v ∈V,满足u->v 或 v - ...

  2. BZOJ1093 [ZJOI2007]最大半连通子图

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

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

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

  4. BZOJ1093 最大半连通子图

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

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

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

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

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

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

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

  8. [BZOJ]1093 最大半连通子图(ZJOI2007)

    挺有意思的一道图论. Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:∀u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v ...

  9. bzoj 1093 最大半连通子图 - Tarjan - 拓扑排序 - 动态规划

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

随机推荐

  1. react基础语法(二)常用语法如:样式 ,自定义属性,常用表达式

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  2. EasyX库进行图片绘制函数

    引用函数:loadimage参数: // 从图片文件获取图像(bmp/jpg/gif/emf/wmf/ico)void loadimage( IMAGE* pDstImg, // 保存图像的 IMAG ...

  3. ssget使用方法

    语法: (ssget [sel-method] [pt1 [pt2]] [pt-list] [filter-list]) ssget 的参数均为可选参数,需要注意的是可选参数之间的组合条件.以下语法表 ...

  4. python读取绝对路径的三种方式

    import pandas as pd dood_inf0=pd.read_csv("C:\\Users\\Administrator\\Desktop\\food_info.csv&quo ...

  5. HDU6199 gems gems gems (DP)

    题意:有n颗石子 两个人轮流拿 如果上一个人拿了x颗 这个人就可以拿x或x+1颗 问先手能获得与后手的价值差最大是多少 题解:看起来是博弈 其实是DP dp[i][j][0/1]表示当前该0/1拿 拿 ...

  6. [模板] Miller-Rabin 素数测试

    细节挺多的.. #include<iostream> #include<cstdlib> #include<cstdio> #include<ctime> ...

  7. Springboot整合Shiro安全框架

    最近在学习Springboot,在这个过程中遇到了很多之前都没有技术知识,学习了一阵子,稍微总结一些. ---- Shiro框架 shiro框架,是一个相对比较简便的安全框架,它可以干净利落地处理身份 ...

  8. turtle安装问题

    原文来源:https://blog.csdn.net/liudongdong19/article/details/81283942 本人python版本为:Python 3.6.5 在安装turtle ...

  9. openjdk-alpine镜像无法打印线程堆栈和内存堆栈问题

    基于openjdk:8u171-alpine构建的java镜像,使用jstack命令打印线程的时候会提示以下错误: /opt # ps -ef PID USER TIME COMMAND 1 root ...

  10. ssh服务介绍

    基本介绍 ssh:安全的远程登陆 要有客户端与服务器端,客户端主动链接服务端,那么服务端地址是不能变的. socket:套接字 标识应用唯一的地址 tcp/udp port端口号 cat /etc/s ...