最大半连通子图

Time Limit: 30 Sec  Memory Limit: 162 MB
[Submit][Status][Discuss]

Description

  一个有向图G=(V,E)称为半连通的(Semi-Connected):

  如果满足:∀u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径。

  若G'=(V',E')满足V'∈V,E'是E中所有跟V'有关的边,则称G'是G的一个导出子图。

  若G'是G的导出子图,且G'半连通,则称G'为G的半连通子图。

  若G'是G所有半连通子图中包含节点数最多的,则称G'是G的最大半连通子图。

  给定一个有向图G,请求出G的最大半连通子图拥有的节点数K ,以及不同的最大半连通子图的数目C。

  由于C可能比较大,仅要求输出C对X的余数。

Input

  第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述。

  接下来M行,每行两个正整数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。

Output

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

Sample Input

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

Sample Output

  3
  3

HINT

  N ≤100000, M ≤1000000;对于100%的数据, X ≤10^8

Main idea

  求最大半联通子图大小与个数。(最大半联通子图定义:在这个图内对于任意节点u,v,存在一条u->v的路径)

Solution

  先跑一遍Tarjan,得到了两两连通的图,然后考虑如何加入单向连通的点集,显然两个强连通分量之间要是有连边的话,就可以满足这两个强连通分量的点单向连通,符合题意。

  那么答案显然就是在缩点后的DAG(有向无环图)上的最长路径

  用拓扑+DP(本质是在拓扑序上的DP)可以求出即为Ans,然后在跑的时候用一个数组f[i]统计一下相同的个数,注意更新dist的时候也要更新f,最后如果dist[i]=Ans,那么累加f[i],即为答案。

Code

 #include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std; const int ONE=; int n,m,MOD;
int x,y;
int Next[ONE],First[ONE],Go[ONE],tot;
int next[ONE],first[ONE],go[ONE],Input[ONE];
int dist[ONE];
int T,t;
int tou,wei,jishu;
int q[ONE];
int Ans,num,f[ONE];
int Dfn[ONE],Low[ONE],vis[ONE],F[ONE],Num[ONE]; struct power
{
int u,v;
}a[ONE]; int cmp(const power &a,const power &b)
{
if(a.u==b.u) return a.v<b.v;
return a.u<b.u;
} int rule(const power &a,const power &b)
{
return (a.u==b.u && a.v==b.v);
} int get()
{
int res,Q=; char c;
while( (c=getchar())< || c>)
if(c=='-')Q=-;
if(Q) res=c-;
while((c=getchar())>= && c<=)
res=res*+c-;
return res*Q;
} int Add(int u,int v)
{
Next[++tot]=First[u]; First[u]=tot; Go[tot]=v;
} int Add_edge(int u,int v)
{
next[++tot]=first[u]; first[u]=tot; go[tot]=v; Input[v]++;
} void Tarjan(int u)
{
Dfn[u]=Low[u]=++T;
vis[u]=;
q[++t]=u;
int v;
for(int e=First[u];e;e=Next[e])
{
int v=Go[e];
if(!Dfn[v])
{
Tarjan(v);
Low[u]=min(Low[u],Low[v]);
}
else if(vis[v])
Low[u]=min(Low[u],Dfn[v]);
} if(Low[u]==Dfn[u])
{
jishu++;
do
{
v=q[t--];
F[v]=jishu;
vis[v]=;
Num[jishu]=Num[jishu]+;
}while(v!=u);
}
} void Rebuild()
{
num=;
for(int u=;u<=n;u++)
{
for(int e=First[u];e;e=Next[e])
{
int v=Go[e];
if(F[u]!=F[v])
{
a[++num].u=F[u];
a[num].v=F[v];
}
}
} sort(a+,a+num+,cmp);
num=unique(a+,a+num+,rule)--a; for(int i=;i<=num;i++)
{
Add_edge(a[i].u,a[i].v);
}
} void Topufirst()
{
for(int v=;v<=jishu;v++)
{
if(!Input[v]) q[++wei]=v;
dist[v]=Num[v];
f[v]=;
Ans=max(Ans,dist[v]);
}
} void TopuA()
{
while(tou<wei)
{
int u=q[++tou];
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(dist[v]<dist[u]+Num[v])
{
dist[v]=dist[u]+Num[v];
f[v]=f[u];
Ans=max(Ans,dist[v]);
}
else
if(dist[v]==dist[u]+Num[v]) f[v]=(f[v]+f[u])%MOD;
if(!(--Input[v])) q[++wei]=v;
}
}
} int main()
{
n=get(); m=get(); MOD=get();
for(int i=;i<=m;i++)
{
x=get(); y=get();
Add(x,y);
} for(int i=;i<=n;i++)
if(!Dfn[i]) Tarjan(i); tot=;
Rebuild(); tou=; wei=;
Topufirst(); TopuA(); tot=;
for(int i=;i<=jishu;i++)
if(dist[i]==Ans) tot=(tot+f[i])%MOD; printf("%d\n%d",Ans,tot);
}

【BZOJ1093】【ZJOI2007】最大半联通子图 [DP][Tarjan]的更多相关文章

  1. 【BZOJ1093】[ZJOI2007]最大半联通子图(Tarjan,动态规划)

    [BZOJ1093][ZJOI2007]最大半联通子图(Tarjan,动态规划) 题面 BZOJ 洛谷 洛谷的讨论里面有一个好看得多的题面 题解 显然强连通分量对于题目是没有任何影响的,直接缩点就好了 ...

  2. bzoj1093 [ZJOI2007]最大半联通子图 缩点 + 拓扑序

    最大半联通子图对应缩点后的$DAG$上的最长链 复杂度$O(n + m)$ #include <cstdio> #include <cstring> #include < ...

  3. bzoj1093[ZJOI2007]最大半连通子图(tarjan+拓扑排序+dp)

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

  4. BZOJ1093 [ZJOI2007]最大半连通子图 【tarjan缩点 + DAG最长路计数】

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

  5. [ZJOI2007]最大半连通子图(Tarjan,拓扑序DP)

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

  6. [bzoj 1093][ZJOI2007]最大半联通子图(强联通缩点+DP)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1093 分析: 首先肯定是先把强联通全部缩成一个点,然后成了一个DAG 下面要知道一点: ...

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

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

  8. 【tarjan 拓扑排序 dp】bzoj1093: [ZJOI2007]最大半连通子图

    思维难度不大,关键考代码实现能力.一些细节还是很妙的. Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于 ...

  9. bzoj1093: [ZJOI2007]最大半连通子图 scc缩点+dag上dp

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

随机推荐

  1. Java 二维数组

    在 Java 中,二维数组与一维数组一样,但是不同于 C 中的二维数组: 1. 在 Java 中,二维数组可以看成是以数组为元素的数组,例如:  int a[][] = {{1,2},{3,4,5,6 ...

  2. VS2013 “未找到与约束 ContractName Microsoft.Internal.VisualStudio.PlatformUI.ISolutionAttachedCollectionService RequiredTypeIdentity Microsoft.Internal.VisualStudio.PlatformUI.ISolutionAttachedCollectionService 匹配的导出”

    下面是我出错误的附加图片 这个错误导致无法打开项目. 解决方法: 解: C:\Users\Administrator\AppData\Local\Microsoft\VisualStudio\12.0 ...

  3. WE团队团队汇总

    WE团队目录 一.博客汇总 团队展示 选题报告 二.文档汇总 选题报告

  4. 【Linux】- Ubuntu安装nginx

    安装 执行命令: sudo apt-get install nginx 执行如图: 防火墙设置 查看防火墙状态: sudo ufw status 查看可以穿过防火墙的应用列表: sudo ufw ap ...

  5. 第45天:2017webstrom下载破解汉化

    1.webstrom 11.0.3下载地址1:http://pan.baidu.com/s/1kVQjcwf 密码:uggr 下载地址2:http://pan.baidu.com/s/1kVQjcwf ...

  6. Abp的AspNetZero5.0版本无法使用ctrl+f5调式

    AspNetZero是基于Abp框架开发的商业程序,最近从Abp交流群中得知5.0版本开始加入了防盗版的功能,在vs中也无法使用ctrl+f5进行调试.经过两天的摸索,我发现不能进行调试的原因也是因为 ...

  7. 51nod1469 淋漓字符串(后缀自动机)

    题目大意: 首先,我们来定义一下淋漓尽致子串. 1.令原串为S. 2.设子串的长度为len,在原串S中出现的次数为k,令其出现的位置为p1, p2, ....pk(即这个子串在原串中[pi,pi + ...

  8. css边框以及其他常用样式

    1. 边框是1像素,实体的,红色的. <!DOCTYPE html> <html lang="en"> <head> <meta char ...

  9. springboot 在tomcat中启动两次

    我开始以为眼花了,tomcat启动的时候, .   ____          _            __ _ _ /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \( ...

  10. YBT 5.2 树形动态规划

    题解在代码中 二叉苹果树[loj 10153] /* 若要留q条边便是要留q+1个点 所以记忆化搜索 dp[pos][ans]=max(dp[pos][ans],dp[l[pos]][k]+dp[r[ ...