P2272 [ZJOI2007]最大半连通子图

萌新初学Tarjan,在《信息学奥赛一本通-提高篇》中看到这题,看到题解不多,便想发布一篇较为清新简洁的题解。——第5道紫题

题目大意:

定义最大半连通图:对于图中任意两点u,v,存在一条u到v的有向路径 或者 从v到u的有向路径。求一个图中不同的最大半连通子图的数目。

看到题面时大家很容易想到,如果两点互相可以到达,那么它们必是半连通图,所以考虑先Tarjan缩点(P3387 【模板】缩点(Tarjan缩点+DAGdp)

接着去除重边重新建图,你会发现,在这个有向无环图(DAG)中,半连通子图都是一条链(可以举反例试试,这条链不可能有分支,否则将有两点无法抵达另一方)

于是,G的最大半连通子图拥有的节点数K就是最长链长度,不同的最大半连通子图的数目就是最长链个数。

信息学一本通:最长链可以直接用拓扑排序(topo),最长链个数用一个类似DP的方法,用f【i】表示以 i 为终点的方案数,那么f【i】就等于满足距离为起点到 i 的临时最短距离的点的 f 的和。然后查找距离等于最长链的点,答案为它们的方案数之和

其他题解中已经给出了拓扑的算法,我借鉴大佬的程序用的是搜索,先一直搜到终点再回来更新答案。由于数据范围#7一直RE,后来改为const int N=1e5+5,M=2e6+5;终于AC。。qwq高性能。。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int N=1e5+5,M=2e6+5; bool f[N];
//f 在搜索中判断是否走过 int n,m,mod,now,d[N],a[N],ans,maxans,ch[N];
//d指从u到终点的最长链距离,a指最长链点数,ch指出度 int h[N],u[M],v[M],r[N],nu[M],cnt;
//h是链式前向星的建边head,u,v保存初始读入的边左右两点,nu存初始时边的编号,r是入度 int top,co,dfn[N],low[N],c[N],s[N],st[N];
//dfn,low,st用于Tarjan,c表所在强连通分量编号,s指所在强连通分量点数 struct edge {
int h,to;
} e[M]; #define rint register int
#define min(a,b) (a<b? a:b)
#define max(a,b) (a>b? a:b) inline bool cmp(int a,int b) {
return u[a]<u[b] || (u[a]==u[b] && v[a]<v[b]);
}//将边排序,方便重新建图 inline void add(int u,int v) {
e[++cnt].h=h[u],h[u]=cnt,e[cnt].to=v;
} inline int read() {
int w=1,ans=0;
char ch=getchar();
while(ch>'9'||ch<'0') if (ch=='-') w=-1,ch=getchar();
while(ch<='9'&& ch>='0') ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans*w;
} inline void Tarjan(int u) {
dfn[u]=low[u]=++now;
st[++top]=u;
for (rint i=h[u]; i; i=e[i].h) {
int v=e[i].to;
if (!dfn[v])
Tarjan(v),low[u]=min(low[u],low[v]);
else if (!c[v])
low[u]=min(low[u],dfn[v]);
}
if (low[u]==dfn[u]) {
c[u]=++co,s[co]++;
while(st[top]!=u)
s[co]++,c[st[top]]=co,top--;
top--;
}
}//标准缩点 inline void dfs(int u) {
f[u]=1;
if (!ch[u]) {//如果没有出度,即到头了
d[u]=s[u],a[u]=1;//距离为点数,以u为起点方案为1
maxans=max(maxans,d[u]);//更新最长链距离
return;
}
for (rint i=h[u]; i; i=e[i].h) {
int v=e[i].to;
if (!f[v]) dfs(v);//继续搜索链的后面
if (d[v]+s[u]>d[u])//若以u为起点的链距离可以更长
d[u]=d[v]+s[u],a[u]=a[v]%mod;//更新
else if (d[u]==d[v]+s[u])//若最长链距离相同
a[u]=(a[u]+a[v])%mod;//加上方案数
maxans=max(maxans,d[u]);
}
} int main() {
n=read(),m=read(),mod=read();
for (rint i=1; i<=m; i++) u[i]=read(),v[i]=read(),add(u[i],v[i]);
for (rint i=1; i<=n; i++) if (!dfn[i]) Tarjan(i); cnt=0;
memset(h,0,sizeof h);
memset(e,0,sizeof e);
for (rint i=1; i<=m; i++)
nu[i]=i,u[i]=c[u[i]],v[i]=c[v[i]]; sort(nu+1,nu+m+1,cmp);//按u,v排序边
for (rint i=1; i<=m; i++)
{
int num=nu[i];
if (u[num]!=v[num] && (u[num]!=u[nu[i-1]] || v[num]!=v[nu[i-1]]))//若此边不是自环,且与上一条边不同(去除重边)
++ch[u[num]],++r[v[num]],add(u[num],v[num]);}
//出度入度加1,加边
for (rint i=1; i<=co; i++) if (!r[i] && !f[i]) dfs(i);//入度为0且未搜索过
for (rint i=1; i<=co; i++) if (d[i]==maxans) ans=(ans+a[i])%mod;//统计答案
printf("%d\n%d\n",maxans,ans);
}

题解 P2272 【[ZJOI2007]最大半连通子图】的更多相关文章

  1. 洛谷 P2272 [ZJOI2007]最大半连通子图 解题报告

    P2272 [ZJOI2007]最大半连通子图 题目描述 一个有向图\(G=(V,E)\)称为半连通的\((Semi-Connected)\),如果满足:\(\forall u,v \in V\),满 ...

  2. Luogu P2272 [ZJOI2007]最大半连通子图(Tarjan+dp)

    P2272 [ZJOI2007]最大半连通子图 题意 题目描述 一个有向图\(G=(V,E)\)称为半连通的\((Semi-Connected)\),如果满足:\(\forall u,v\in V\) ...

  3. luogu P2272 [ZJOI2007]最大半连通子图

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

  4. P2272 [ZJOI2007]最大半连通子图 tarjan+DP

    思路:$tarjan+DP$ 提交:1次 题解:首先对于一个强连通分量一定是一个半连通分量,并且形成的半连通分量的大小一定是它的$size$,所以我们先缩点. 这样,我们相当于要在新的$DAG$上找一 ...

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

    思路 tarjan的题目 注意是要选出一个点集而不是边集 第一问就是缩点之后最长链,第二问就是有多少个最长链,注意缩点后连边要去重(不然一个链的方案可能会被统计多次) 代码 #include < ...

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

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

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

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

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

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

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

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

随机推荐

  1. scons编译mongodb(vs2008版本)遇到的问题总结

    OS:win7 64 boost:1.49 mongodb:2.4.6(推荐64位版本,当然如果你系统是32位的,只能使用32的版本了) IDE:vs2008(2010的同学请跳过吧,因为官网提供的就 ...

  2. QT5.1编译后的安装目录问题(硬路径问题)

    这个是我的编译参数:configure -ltcg -confirm-license -opensource -platform win32-msvc2010 -debug-and-release - ...

  3. Flask在VSCODE下基本开发环境配置

    1.创建环境 cd /project/path python3 -m venv venv 第一个VENV是命令,第二个是文件夹名 如果环境不要了,一般做法是直接整个(VENV)文件夹删掉 环境修改下面 ...

  4. 不仅仅是百万级TCP长连接框架 t-io

    t-io: 不仅仅是百万级TCP长连接框架 t-io是基于jdk aio实现的易学易用.稳定.性能强悍.将多线程运用到极致.内置功能丰富的即时通讯框架(广义上的即时通讯,并非指im),字母 t 寓意t ...

  5. IO多路复用与异步非阻塞

    1.基于socket,发送http请求 import socket import requests # 方式一 list=['li','gh ','nn'] for i in list: ret=re ...

  6. SYN1618型 高精度天文时间同步系统

       SYN1618型 高精度天文时间同步系统 产品概述 SYN1618型 高精度天文时间同步系统是由西安同步电子科技有限公司精心设计.自行研发生产的一款高精度的时频频率标准设备,接收GPS.GLON ...

  7. kafka笔记4

    应用程序使用KafkaConsumer向Kafka订阅主题,并从订阅的主题上接收消息.Kafka消费者从属于消费者群组,一个群组里的消费者订阅的是同一个主题,每个消费者接收主题的一部分分区的消息. 一 ...

  8. win10 下的YOLOv3 训练 wider_face 数据集检测人脸

    1.数据集下载 (1)wider_face 数据集网址为 http://shuoyang1213.me/WIDERFACE/index.html 下载以上几项文件(这里推荐 google Drive ...

  9. Docker容器化部署Python应用

    1. 简介 Docker是目前主流IT公司广泛接受和使用的,用于构建.管理和保护它们应用程序的工具. 容器,例如Docker允许开发人员在单个操作系统上隔离和运行多个应用程序,而不是为服务器上的每个应 ...

  10. Centos7 fstab盘符挂载硬盘导致重启系统失败解决办法

    服务器拥有多个硬盘插槽,在进行维护或重启时,这些硬盘的相对位置可能发生变化.利用盘符(dev/vda)方式挂载磁盘,可能由于磁盘顺序变化导致重启时读取fstab文件发生错误,从而无法正常重启服务器. ...