P2272 [ZJOI2007]最大半连通子图

题意

题目描述

一个有向图\(G=(V,E)\)称为半连通的\((Semi-Connected)\),如果满足:\(\forall u,v\in V\),满足\(u\rightarrow v\)或\(v\rightarrow u\),即对于图中任意两点\(u,v\),存在一条\(u\)到\(v\)的有向路径或者从\(v\)到\(u\)的有向路径。若\(G^\prime=(V^\prime,E^\prime)\)满足\(V^\prime\in V\),\(E^\prime\)是\(E\)中所有跟\(V^\prime\)有关的边,则称\(G^\prime\)是\(G\)的一个导出子图。若\(G^\prime\)是\(G\)的导出子图,且\(G^\prime\)半连通,则称\(G^\prime\)为\(G\)的半连通子图。若\(G^\prime\)是\(G\)所有半连通子图中包含节点数最多的,则称\(G^\prime\)是\(G\)的最大半连通子图。给定一个有向图\(G\),请求出\(G\)的最大半连通子图拥有的节点数\(K\),以及不同的最大半连通子图的数目\(C\)。由于\(C\)可能比较大,仅要求输出\(C\)对\(X\)的余数。

输入格式

第一行包含两个整数\(N,M,X\)。\(N,M\)分别表示图\(G\)的点数与边数,\(X\)的意义如上文所述接下来M行,每行两个正整数\(a,b\),表示一条有向边\((a,b)\)。图中的每个点将编号为\(1,2,3\dots N\),保证输入中同一个\((a,b)\)不会出现两次。

输出格式

应包含两行,第一行包含一个整数\(K\)。第二行包含整数\(C\mod X\)。

输入输出样例

输入样例#1:

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

输出样例#1:

3
3

说明

对于\(100\%\)的数据,\(N\le 100000,M\le 1000000,X\le 10^8\)。

思路

先来想两个问题:

  1. 该图是强连通图,那么答案是多少?
  2. 该图是有向无环图,那么答案是多少?

对于第一个问题,任意两点互相可达,问题变得很简单,答案就是原图;对于第二个问题,我们可以直接\(DAG\ DP\)完美解决。

那么对于任意的一张图,我们用\(Tarjan\)缩点之后,答案不久呼之欲出了吗?所以这题只需要在缩点之后的图上\(DP\)就好了。

不过还有个细节:因为要求方案数,所以不能建重边。比如点\(1\)向点\(2\)建了两条边。从\(1\)点向周围拓展时,第一次扫描到\(2\),我们更新了\(2\)的答案;第二次扫描到\(2\),我们又更新了\(2\)的答案。这显然是不被允许的。所以开个\(set\)判断一下重边就好啦。

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> PLL;
const LL MAXN=1e5+5,MAXM=1e6+5;
LL n,m,p,ans1,ans2,tot,dfn[MAXN],low[MAXN];
LL cnt,top[MAXN],to[MAXM],nex[MAXM];
LL _cnt,_top[MAXN],_to[MAXM],_nex[MAXM];
LL js,bel[MAXN],sz[MAXN],deg[MAXN],val[MAXN],tms[MAXN];
bool vis[MAXN];
stack<LL>S;
set<PLL>SS;
LL read()
{
LL re=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
return re;
}
void tarjan(LL now)
{
dfn[now]=low[now]=++tot,vis[now]=true,S.push(now);
for(LL i=top[now];i;i=nex[i])
if(!dfn[to[i]]) tarjan(to[i]),low[now]=min(low[now],low[to[i]]);
else if(vis[to[i]]) low[now]=min(low[now],dfn[to[i]]);
if(dfn[now]==low[now])
{
bel[now]=++js,vis[now]=false,sz[js]=1;
while(S.top()!=now) bel[S.top()]=js,vis[S.top()]=false,sz[js]++,S.pop();
S.pop();
}
}
void work()
{
memset(vis,false,sizeof vis);
queue<LL>Q;
for(LL i=1;i<=js;i++) if(!deg[i]) val[i]=sz[i],tms[i]=1,Q.push(i);
while(!Q.empty())
{
LL now=Q.front();Q.pop();
for(LL i=_top[now];i;i=_nex[i])
{
deg[_to[i]]--;
if(vis[_to[i]]) continue;
vis[_to[i]]=true;
if(val[_to[i]]<val[now]+sz[_to[i]]) val[_to[i]]=val[now]+sz[_to[i]],tms[_to[i]]=tms[now];
else if(val[_to[i]]==val[now]+sz[_to[i]]) tms[_to[i]]=(tms[_to[i]]+tms[now])%p;
if(!deg[_to[i]]) Q.push(_to[i]);
}
for(LL i=_top[now];i;i=_nex[i]) vis[_to[i]]=false;
}
}
int main()
{
n=read(),m=read(),p=read();
while(m--)
{
LL x=read(),y=read();
to[++cnt]=y,nex[cnt]=top[x],top[x]=cnt;
}
for(LL i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
for(LL i=1;i<=n;i++)
for(LL j=top[i];j;j=nex[j])
if(bel[i]!=bel[to[j]])
{
if(SS.find(make_pair(bel[i],bel[to[j]]))!=SS.end()) continue;
_to[++_cnt]=bel[to[j]],_nex[_cnt]=_top[bel[i]],_top[bel[i]]=_cnt,deg[bel[to[j]]]++;
SS.insert(make_pair(bel[i],bel[to[j]]));
}
work();
for(LL i=1;i<=js;i++)
if(ans1<val[i]) ans1=val[i],ans2=tms[i];
else if(ans1==val[i]) ans2=(ans2+tms[i])%p;
printf("%lld\n%lld",ans1,ans2);
return 0;
}

Luogu P2272 [ZJOI2007]最大半连通子图(Tarjan+dp)的更多相关文章

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

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

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

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

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

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

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

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

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

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

  6. 【bzoj1093】[ZJOI2007]最大半连通子图 Tarjan+拓扑排序+dp

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

  7. [luogu2272 ZJOI2007] 最大半连通子图 (tarjan缩点 拓扑排序 dp)

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

  8. [ZJOI2007]最大半连通子图 (Tarjan缩点,拓扑排序,DP)

    题目链接 Solution 大概是个裸题. 可以考虑到,如果原图是一个有向无环图,那么其最大半联通子图就是最长的一条路. 于是直接 \(Tarjan\) 缩完点之后跑拓扑序 DP就好了. 同时由于是拓 ...

  9. BZOJ 1093 [ZJOI2007]最大半连通子图 - Tarjan 缩点

    Description 定义一个半联通图为 : 对任意的两个点$u, v$,都有存在一条路径从$u$到$v$, 或从$v$到$u$. 给出一个有向图, 要求出节点最多的半联通子图,  并求出方案数. ...

随机推荐

  1. java反射快速入门

    笔记记在了掘金,发现掘金的markdown编辑器比博客园样式要好看不少 https://juejin.im/post/5d4e575af265da03e4674e9f

  2. 边双联通分量缩点+树的直径——cf1000E

    题意理解了就很好做 题意:给一张无向图,任意取两个点s,t,s->t的路径上必经边数量为k 求这样的s,t,使得k最大 #include<bits/stdc++.h> #define ...

  3. CUDA 关于 BLOCK数目与Thread数目设置

    GPU的计算核心是以一定数量的Streaming Processor(SP)组成的处理器阵列,NV称之为Texture Processing Clusters(TPC),每个TPC中又包含一定数量的S ...

  4. 尚学linux课程---3、linux网络说明

    尚学linux课程---3.linux网络说明 一.总结 一句话总结: 如果NAT模式:linux,VMnet8,虚拟出来的路由器 要在同一个网段, 那么 linux才能 通过 网络地址转换 经过wi ...

  5. laravel装饰者模式例子

    interface Decorator{ public function display(); } class XiaoFang implements Decorator { private $nam ...

  6. Spring事物管理机制简单学习

    首先spring并不直接管理事物,而是提供了多种事物管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现. Spring管理事物的接口是org.s ...

  7. spring boot发简单文本邮件

    首先要去邮箱打开POP3/SMTP权限: 然后会提供个授权码,用来发送邮件.忘记了,可以点生成授权码再次生成. 1.引入spring boot自带的mail依赖,这里版本用的:<spring-b ...

  8. <每日一题>算法题:集合求并集并排序

    题目描述 给你两个集合,要求{A} + {B}. 注:同一个集合中不会有两个相同的元素. 输入描述: 每组输入数据分为三行,第一行有两个数字n,m(0 ≤ n,m ≤ 10000),分别表示集合A和集 ...

  9. VMware Workstation 10 配置Ubuntu环境

    分享到 一键分享 QQ空间 新浪微博 百度云收藏 人人网 腾讯微博 百度相册 开心网 腾讯朋友 百度贴吧 豆瓣网 搜狐微博 百度新首页 QQ好友 和讯微博 更多... 百度分享 VMware Work ...

  10. Ubuntu环境下使用Maven编译并打包Java项目

    一.安装Maven 打开终端输入以下指令: $ mvn -v Apache Maven Maven home: /usr/share/maven Java version: 1.8.0_181, ve ...