最大半连通子图

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. c++SDK c#调用_疑难杂症

    在编写过程中,会不时遇到各种问题: 1.dll明显在和exe同一目录下但调用不成功, 2.运行正常,没有报错,参数数值运行过程中也一致,但结果就是达不到预想, 都是dll没有引用完全造成的影响. 推荐 ...

  2. c#非界面线程控制控件

    private delegate void FlushCilent(); Invoke(new FlushCilent(databaseConnect));

  3. window.open居中显示

    window.open中会发现怎么打开的浏览器窗口怎么不在正中间,而且还比较随性,那不是逼死强迫症患者了,所以查了一下资料始终打开的窗口能显示在正中间,下面是js中的代码分享 // url 转向网页的 ...

  4. QT分析之调试跟踪系统

    原文地址:http://blog.163.com/net_worm/blog/static/127702419201002004518944/ 在我们前面的分析中,经常看到qWarning()和qDe ...

  5. Zookeeper实现分布式集群监控

    Zookeeepr实现分布式集群监控 Zookeeper中节点有两种:临时节点和永久节点 从类型上看节点又可以分为四种节点类型:PERSIST,PERSIST_SEQUENTIAL,EPHEMERAL ...

  6. [计算机网络-应用层] FTP协议

    文件传输协议:FTP 如下图所示:用户通过一个FTP用户代理与FTP交互.该用户首先提供远程主机的主机名,使本地主机的FTP客户机进程建立一个到远程主机FTP服务器进程的TCP连接.然后,该用户提供用 ...

  7. 第64天:CSS常用命名规范,有用!

    CSS常用命名,必须记住 一.常用命名 标题:title 摘要:summary 箭头:arrow 商标:label 网站标志:logo 转角/圆角:corner 横幅广告:banner 子菜单:sub ...

  8. JavaScript 面向对象开发知识基础总结

    JavaScript 面向对象开发知识基础总结 最近看了两本书,书中有些内容对自己还是很新的,有些内容是之前自己理解不够深的,所以拿出来总结一下,这两本书的名字如下: JavaScript 面向对象精 ...

  9. 以安装PyTorch为例说明Anaconda在Windows/Linux上的使用

    在Windows10上配置完MXNet 1.3.0后,再配置PyTorch 1.0时,发现两者需要依赖的NumPy版本不一致,之前是通过pip安装NumPy,根据pip的版本不同,会安装不同版本的Nu ...

  10. Android View 绘制刷新流程分析

    Android中对View的更新有很多种方式,使用时要区分不同的应用场合.1.不使用多线程和双缓冲      这种情况最简单,一般只是希望在View发生改变时对UI进行重绘.你只需显式地调用View对 ...