[ZJOI2007]最大半连通子图(Tarjan,拓扑序DP)
[ZJOI2007]最大半连通子图
题目描述
一个有向图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的余数。
输入输出格式
输入格式:
第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述接下来M行,每行两个正整数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…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\)
Tarjan+拓扑序DP
在一个强联通分量里的点可以互相到达,所以我们先缩点,减少处理情况。
现在图变成了一张有向无环图,对于求出最多的节点数显然可以用拓扑排序求出,而对于第二问的方案数写个DP即可,具体见代码。
最近总出数组开小这种蛇皮错误qwq。
#include<bits/stdc++.h>
#define Min(a,b) (a)<(b)?(a):(b)
#define Max(a,b) (a)>(b)?(a):(b)
using namespace std;
int read()
{
int x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*w;
}
const int N=100010;
int n,m,cnt,mod,top,visnum,scc,ans1,ans2,qwe,jishu;
int head[N],x[10*N],y[10*N],du[N];
int dfn[N],low[N],s[N],num[N],sum[N],belong[N],dp[N];
bool in[N];
struct node{
int to,next;
}edge[20*N];
struct Node{
int x,y;
}f[10*N];
queue<int>q;
bool cmp(Node p,Node q){if(p.x==q.x)return p.y<q.y;return p.x<q.x;}
void add(int x,int y)
{
cnt++;edge[cnt].to=y;edge[cnt].next=head[x];head[x]=cnt;
}
void tarjan(int k)
{
int v;
dfn[k]=low[k]=++visnum;
s[++top]=k;in[k]=1;
for(int i=head[k];i;i=edge[i].next)
{
v=edge[i].to;
if(!dfn[v])
{
tarjan(v);low[k]=Min(low[k],low[v]);
}
else if(in[v]) low[k]=Min(low[k],dfn[v]);
}
if(dfn[k]==low[k])
{
v=-1;scc++;
while(v!=k)
{
v=s[top--];in[v]=0;num[scc]++;belong[v]=scc;
}
}
}
int main()
{
n=read();m=read();mod=read();
for(int i=1;i<=m;i++)
{
x[i]=read();y[i]=read();add(x[i],y[i]);
}
for(int i=1;i<=n;i++)
{
if(!dfn[i]) tarjan(i);
}
cnt=0;memset(head,0,sizeof(head));
for(int i=1;i<=m;i++)
{
int xx=belong[x[i]],yy=belong[y[i]];
if(xx!=yy) {qwe++;f[qwe].x=xx;f[qwe].y=yy;}
}
sort(f+1,f+1+qwe,cmp);
for(int i=1;i<=qwe;i++)
{
if(f[i].x==f[i-1].x&&f[i].y==f[i-1].y) continue;
add(f[i].x,f[i].y);du[f[i].y]++;
}
for(int i=1;i<=scc;i++)
{
if(!du[i]) q.push(i),sum[i]=num[i],dp[i]=1;
}
while(q.size())
{
int u=q.front();q.pop();jishu++;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
du[v]--;
if(sum[v]<sum[u]+num[v]) sum[v]=sum[u]+num[v],dp[v]=dp[u];
else if(sum[v]==sum[u]+num[v]) dp[v]+=dp[u];
dp[v]%=mod;
if(!du[v]) q.push(v);
}
}
for(int i=1;i<=scc;i++)
{
if(sum[ans1]<sum[i]) ans1=i,ans2=dp[i];
else if(sum[ans1]==sum[i]) ans2+=dp[i];
ans2%=mod;
}
printf("%d\n%d",sum[ans1],ans2);
}
[ZJOI2007]最大半连通子图(Tarjan,拓扑序DP)的更多相关文章
- 【bzoj1093】[ZJOI2007]最大半连通子图 Tarjan+拓扑排序+dp
题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:对于u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径. ...
- BZOJ 1093: [ZJOI2007]最大半连通子图( tarjan + dp )
WA了好多次... 先tarjan缩点, 然后题意就是求DAG上的一条最长链. dp(u) = max{dp(v)} + totu, edge(u,v)存在. totu是scc(u)的结点数. 其实就 ...
- Luogu P2272 [ZJOI2007]最大半连通子图(Tarjan+dp)
P2272 [ZJOI2007]最大半连通子图 题意 题目描述 一个有向图\(G=(V,E)\)称为半连通的\((Semi-Connected)\),如果满足:\(\forall u,v\in V\) ...
- [ZJOI2007]最大半连通子图 (Tarjan缩点,拓扑排序,DP)
题目链接 Solution 大概是个裸题. 可以考虑到,如果原图是一个有向无环图,那么其最大半联通子图就是最长的一条路. 于是直接 \(Tarjan\) 缩完点之后跑拓扑序 DP就好了. 同时由于是拓 ...
- [luogu2272 ZJOI2007] 最大半连通子图 (tarjan缩点 拓扑排序 dp)
传送门 题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向 ...
- bzoj 1093 最大半连通子图 - Tarjan - 拓扑排序 - 动态规划
一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G'=(V ...
- BZOJ1093: [ZJOI2007]最大半连通子图(tarjan dp)
题意 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径.若G' ...
- BZOJ1093 ZJOI2007最大半连通子图(缩点+dp)
发现所谓半连通子图就是缩点后的一条链之后就是个模板题了.注意缩点后的重边.写了1h+真是没什么救了. #include<iostream> #include<cstdio> # ...
- BZOJ 1093 [ZJOI2007]最大半连通子图 - Tarjan 缩点
Description 定义一个半联通图为 : 对任意的两个点$u, v$,都有存在一条路径从$u$到$v$, 或从$v$到$u$. 给出一个有向图, 要求出节点最多的半联通子图, 并求出方案数. ...
- P2272 [ZJOI2007]最大半连通子图 tarjan+DP
思路:$tarjan+DP$ 提交:1次 题解:首先对于一个强连通分量一定是一个半连通分量,并且形成的半连通分量的大小一定是它的$size$,所以我们先缩点. 这样,我们相当于要在新的$DAG$上找一 ...
随机推荐
- Oracle dba角色和sysdba的区别
如果用户需要远程sysdba的方式登陆,需要grant sysdba权限,登陆后以sys用户执行命令,需要验证密码文件. 密码文件如果是从12c之前的老版本同步过来,需要重建12c格式的密码文件. d ...
- JVM参数设置-jdk8参数设置
JVM参数设置 1.基本参数 参数名称 含义 默认值 -Xms 初始堆大小 内存的1/64 默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx ...
- 【ABAP系列】SAP ABAP 控制ALV单元格编辑后获取新的数值
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 控制ALV单元 ...
- Lesson 4 The double life of Alfred Bloggs
There are two type of people in the society. People who do manual works can higher payment than peop ...
- vue2.0父子组件通信以及同级组件通信
1.父向子通信 父组件为singer.vue.子组件为list-view.vue.需要把歌手的数据传给子组件.则绑定 :data = 'singers' ,singers为父组件的值.data为子组件 ...
- Canvas入门05-渐变颜色
线性渐变API: ctx.createLinearGradient(double x1, double y1, double x2, double y2) 创建一个渐变实例 (x1, y1) 渐变的起 ...
- Java - Java Mail邮件开发(2)springboot +Java Mail + Html
1.springboot + Java Mail + Html 项目结构: pom.xml <project xmlns="http://maven.apache.org/POM/4. ...
- Cyclic Nacklace HDU 3746 KMP 循环节
Cyclic Nacklace HDU 3746 KMP 循环节 题意 给你一个字符串,然后在字符串的末尾添加最少的字符,使这个字符串经过首尾链接后是一个由循环节构成的环. 解题思路 next[len ...
- Linux如何设置在当前目录下打开终端
转:https://blog.csdn.net/iot_flower/article/details/71189816 1. sudo apt-get install nautilus-open-te ...
- OI那些事——AFO
\(OI\)那些事--\(AFO\) 世界上从此少了一个\(Oier\)也不会有人知道,也许只有某个人在某年某月某日翻到了Eternal 风度的博客才会发现:哇,这哥们怎么\(Noip\)就退役了 两 ...