最大半连通子图

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. 20145214 《Java程序设计》第6周学习总结

    20145214 <Java程序设计>第6周学习总结 教材学习内容总结 串流设计 Java将输入/输出抽象化为串流,数据有来源及目的地,衔接两者的是串流对象. 输入串流代表对象为java. ...

  2. 2019寒假训练营寒假作业(二) MOOC的网络空间安全概论笔记部分

    视频课程--MOOC的网络空间安全概论笔记 第一章 网络空间安全概述 2001年,网络空间概念被首次提出: 网络空间安全框架: 1.设备层安全: 可通过截获电磁辐射获取计算机信息.通过硬件木马(恶意电 ...

  3. Uncaught Error: Syntax error, unrecognized expression: |117的js错误

    117指的是js代码在浏览器运行时的出错的行号 var  a="117|117" 前面的错误是由于有特殊符号“|”,用$("txtId"+a).val();去取 ...

  4. ubuntu中下载sublime相关问题

    1.SublimeText3的安装 在网上搜索了一些ubuntu下关于sublime-text-3安装的方法,在这里针对自己尝试的情况进行反馈: 方法一(未成功): 在终端输入以下代码: sudo a ...

  5. 原生js移动端可拖动进度条插件

    该插件最初的想法来自网上的一篇文章,直达链接:https://www.cnblogs.com/libin-1/p/6220056.html 笔者因为业务需要寻找到这个插件,然后拿来用之,发现各种不方便 ...

  6. 通过access_token openid获取微信用户昵称等信息

    <?php header('Access-Control-Allow-Origin:*'); $access_token = !empty($_GET['access_token'])?$_GE ...

  7. 【Docker 命令】- inspect命令

    docker inspect : 获取容器/镜像的元数据. 语法 docker inspect [OPTIONS] NAME|ID [NAME|ID...] OPTIONS说明: -f :指定返回值的 ...

  8. 网络控制API 路由表 arp表 包括tcp的这些参数都是从哪里设置

    路由表查看 arp缓存 都是走的什么接口?

  9. js 复制到剪贴板 兼容还得自己想办法

    clipboard.js https://github.com/zenorocha/clipboard.js/ 主要问题还是ie8, 可以使用ie 特有的方法 if (window.clipboard ...

  10. [洛谷P5105]不强制在线的动态快速排序

    题目大意:有一个可重集$S$,有两个操作: $1\;l\;r:$表示把$S$变为$S\cup[l,r]$ $2:$表示将$S$从小到大排序,记为$a_1,a_2,\dots,a_n$,然后求出$\bi ...