Luogu P2272 [ZJOI2007]最大半连通子图(Tarjan+dp)
题意
题目描述
一个有向图\(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\)。
思路
先来想两个问题:
- 该图是强连通图,那么答案是多少?
- 该图是有向无环图,那么答案是多少?
对于第一个问题,任意两点互相可达,问题变得很简单,答案就是原图;对于第二个问题,我们可以直接\(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)的更多相关文章
- P2272 [ZJOI2007]最大半连通子图 tarjan+DP
思路:$tarjan+DP$ 提交:1次 题解:首先对于一个强连通分量一定是一个半连通分量,并且形成的半连通分量的大小一定是它的$size$,所以我们先缩点. 这样,我们相当于要在新的$DAG$上找一 ...
- BZOJ 1093: [ZJOI2007]最大半连通子图( tarjan + dp )
WA了好多次... 先tarjan缩点, 然后题意就是求DAG上的一条最长链. dp(u) = max{dp(v)} + totu, edge(u,v)存在. totu是scc(u)的结点数. 其实就 ...
- luogu P2272 [ZJOI2007]最大半连通子图
题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若 ...
- BZOJ1093: [ZJOI2007]最大半连通子图(tarjan dp)
题意 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G' ...
- 洛谷 P2272 [ZJOI2007]最大半连通子图 解题报告
P2272 [ZJOI2007]最大半连通子图 题目描述 一个有向图\(G=(V,E)\)称为半连通的\((Semi-Connected)\),如果满足:\(\forall u,v \in V\),满 ...
- 【bzoj1093】[ZJOI2007]最大半连通子图 Tarjan+拓扑排序+dp
题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:对于u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径. ...
- [luogu2272 ZJOI2007] 最大半连通子图 (tarjan缩点 拓扑排序 dp)
传送门 题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向 ...
- [ZJOI2007]最大半连通子图 (Tarjan缩点,拓扑排序,DP)
题目链接 Solution 大概是个裸题. 可以考虑到,如果原图是一个有向无环图,那么其最大半联通子图就是最长的一条路. 于是直接 \(Tarjan\) 缩完点之后跑拓扑序 DP就好了. 同时由于是拓 ...
- BZOJ 1093 [ZJOI2007]最大半连通子图 - Tarjan 缩点
Description 定义一个半联通图为 : 对任意的两个点$u, v$,都有存在一条路径从$u$到$v$, 或从$v$到$u$. 给出一个有向图, 要求出节点最多的半联通子图, 并求出方案数. ...
随机推荐
- java反射快速入门
笔记记在了掘金,发现掘金的markdown编辑器比博客园样式要好看不少 https://juejin.im/post/5d4e575af265da03e4674e9f
- 边双联通分量缩点+树的直径——cf1000E
题意理解了就很好做 题意:给一张无向图,任意取两个点s,t,s->t的路径上必经边数量为k 求这样的s,t,使得k最大 #include<bits/stdc++.h> #define ...
- CUDA 关于 BLOCK数目与Thread数目设置
GPU的计算核心是以一定数量的Streaming Processor(SP)组成的处理器阵列,NV称之为Texture Processing Clusters(TPC),每个TPC中又包含一定数量的S ...
- 尚学linux课程---3、linux网络说明
尚学linux课程---3.linux网络说明 一.总结 一句话总结: 如果NAT模式:linux,VMnet8,虚拟出来的路由器 要在同一个网段, 那么 linux才能 通过 网络地址转换 经过wi ...
- laravel装饰者模式例子
interface Decorator{ public function display(); } class XiaoFang implements Decorator { private $nam ...
- Spring事物管理机制简单学习
首先spring并不直接管理事物,而是提供了多种事物管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现. Spring管理事物的接口是org.s ...
- spring boot发简单文本邮件
首先要去邮箱打开POP3/SMTP权限: 然后会提供个授权码,用来发送邮件.忘记了,可以点生成授权码再次生成. 1.引入spring boot自带的mail依赖,这里版本用的:<spring-b ...
- <每日一题>算法题:集合求并集并排序
题目描述 给你两个集合,要求{A} + {B}. 注:同一个集合中不会有两个相同的元素. 输入描述: 每组输入数据分为三行,第一行有两个数字n,m(0 ≤ n,m ≤ 10000),分别表示集合A和集 ...
- VMware Workstation 10 配置Ubuntu环境
分享到 一键分享 QQ空间 新浪微博 百度云收藏 人人网 腾讯微博 百度相册 开心网 腾讯朋友 百度贴吧 豆瓣网 搜狐微博 百度新首页 QQ好友 和讯微博 更多... 百度分享 VMware Work ...
- Ubuntu环境下使用Maven编译并打包Java项目
一.安装Maven 打开终端输入以下指令: $ mvn -v Apache Maven Maven home: /usr/share/maven Java version: 1.8.0_181, ve ...