最大半连通子图

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中使用extends来实现继承 通过继承,子类自动拥有了基类(supercalss)的所有成员. Java只支持单继承,一个子类只允许有一个基类,一个基类可以有多个子类. class ...

  2. 软工时间-Alpha 冲刺 (2/10)

    队名:起床一起肝活队 组长博客:博客链接 作业博客:班级博客本次作业的链接 组员情况 组员1(队长):白晨曦 过去两天完成了哪些任务 描述: 学习了UI设计软件的使用,了解了项目开发的具体流程. 展示 ...

  3. ACM 第十一天

    多校7题目 GuGuFishtion Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  4. laravel 可用验证规则

    accepted 验证的字段必须为 yes. on. 1.或 true.这在确认服务条款是否同意时相当有用. active_url 相当于使用了 PHP 函数 dns_get_record,验证的字段 ...

  5. 【Linux】CentOS安装redis

    CENTOS7下安装REDIS 安装完成之后使用:redis-cli命令连接,如图: 提示:/var/run/redis_6379.pid exists, process is already run ...

  6. mysql三种备份方式

    一.备份的目的 做灾难恢复:对损坏的数据进行恢复和还原需求改变:因需求改变而需要把数据还原到改变以前测试:测试新功能是否可用 二.备份需要考虑的问题 可以容忍丢失多长时间的数据:恢复数据要在多长时间内 ...

  7. try-with-resources语句

    try-with-resources语句是一种声明了一种或多种资源的try语句.资源是指在程序用完了之后必须要关闭的对象.try-with-resources语句保证了每个声明了的资源在语句结束的时候 ...

  8. 在select中,载入时默认select为空白,选项内不显示空白项

    有两种办法,一种纯css实现,一种借助js实现. html: <body onload="load()"> <select id="abc" ...

  9. springBoot按条件装配:Condition

    编码格式转换器接口 package com.boot.condition.bootconditionconfig.converter; /** * 编码格式转换器接口 */ public interf ...

  10. hdu 1115 Lifting the Stone (数学几何)

    Lifting the Stone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...