[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$上找一 ...
随机推荐
- 第五周学习总结&实验报告(三)
第五周学习总结&实验报告(三) 这一周又学习了新的知识点--继承. 一.继承的基本概念是: *定义一个类,在接下来所定义的类里面如果定义的属性与第一个类里面所拥有的属性一样,那么我们在此就不需 ...
- @清晰掉 C++ 中的 enum 结构在内存中是怎么存储的?
C++ 中的 enum 结构在内存中是怎么存储的? C++ C++ 中的 enum 结构在内存中是怎么存储的?里面存储的是常量值吗? 关于占用内存的大小,enum类型本身是不占内存的,编译器直接 ...
- C++中cout输出字符串和字符串型指针地址值的方法以及C语言中的printf用法比较
#include <iostream> using namespace std; #include <stdio.h> int main() { char *pstr = &q ...
- leetcode-mid-backtracking -46. Permutations-NO
mycode 没有通过,其实只需要把temp.append改为temp+[nums[i]]即可 def permute(nums): def dfs(res,nums,temp): print(num ...
- PADS LAYOUT的一般流程
1.概述 本文档的目的在于说明使用PADS的印制板设计软件PowerPCB进行印制板设计的流程和一些注意事项,为一个工作组的设计人员提供设计规 范,方便设计人员之间进行交流和相互检查. 2.设计 ...
- HTTP缓存初识
一.HTTP缓存 1.强制缓存 2.协商缓存 静态资源 动态资源 二.总结 参考: http://muchstudy.com/2016/08/18/HTTP%E7%BC%93%E5%AD%98%E8% ...
- 浏览器端-W3School:HTML DOM cells 集合
ylbtech-浏览器端-W3School:HTML DOM cells 集合 1.返回顶部 1. HTML DOM cells 集合 HTML DOM Table 对象 定义和用法 cells 集合 ...
- 【工具安装】kali linux 安装教程
日期:2019-07-14 16:36:21 介绍:使用最新版的 VMware 来安装 kali linux 0x01.下载镜像 首先需要安装 VMware,安装步骤点这里. VMware 安装教程 ...
- C#SQL小结
对于c#获取Sql数据目前我采用的是 System.Data.SqlClient.SqlDataReader类. 主要用到如下API: SqlDataReader.Read():每次获取一行的数据,直 ...
- 什么是SLF,PSL,MLF,SLO?
受国际经济金融形势不确定性增强以及各种影响流动性的因素波动较大影响,近年来我国银行体系短期流动性供求的波动性有所加大,尤其是当多个因素相互叠加或市场预期发生变化时,有可能出现市场短期资金供求缺口难以通 ...