【bzoj1093】[ZJOI2007]最大半连通子图 Tarjan+拓扑排序+dp
题目描述
一个有向图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)不会出现两次。N ≤100000, M ≤1000000;对于100%的数据, X ≤10^8
输出
应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.
样例输入
6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4
样例输出
3
3
题解
Tarjan+拓扑排序+dp
显然,如果原图是一个DAG,那么选择的就是一条链,答案就是最长链;
如果不是呢?Tarjan缩点,然后拓扑排序+dp求带权最长链即可。正确性显然。
需要注意的是缩完点后如果有重边需要只考虑一条的贡献,因为确定了点就确定了边的选择,只有一次转移的机会。
时间复杂度 $O(n+m)$
#include <queue>
#include <cstdio>
#include <cctype>
#include <vector>
#include <cstring>
#define N 100010
using namespace std;
queue<int> q;
vector<int> e[N] , v[N];
int p , deep[N] , low[N] , tot , ins[N] , sta[N] , top , bl[N] , si[N] , num , ind[N] , last[N];
struct data
{int x , y;data(int a = 0 , int b = 0) {x = a , y = b;}data operator+(int a) {return data(x + a , y);}data operator^(data a){if(x > a.x) return *this;else if(x < a.x) return a;else return data(x , (y + a.y) % p);}
}f[N];
void tarjan(int x)
{vector<int>::iterator i;deep[x] = low[x] = ++tot , ins[x] = 1 , sta[++top] = x;for(i = e[x].begin() ; i != e[x].end() ; i ++ ){if(!deep[*i]) tarjan(*i) , low[x] = min(low[x] , low[*i]);else if(ins[*i]) low[x] = min(low[x] , deep[*i]);}if(deep[x] == low[x]){int t;num ++ ;do{t = sta[top -- ] , ins[t] = 0;bl[t] = num , si[num] ++ ;}while(t != x);}
}
void solve(int n)
{vector<int>::iterator i;data ans;int x;for(x = 1 ; x <= n ; x ++ )for(i = e[x].begin() ; i != e[x].end() ; i ++ )if(bl[x] != bl[*i])v[bl[x]].push_back(bl[*i]) , ind[bl[*i]] ++ ;for(x = 1 ; x <= num ; x ++ )if(!ind[x])f[x] = data(si[x] , 1) , q.push(x);while(!q.empty()){x = q.front() , q.pop() , ans = ans ^ f[x];for(i = v[x].begin() ; i != v[x].end() ; i ++ ){if(last[*i] != x) last[*i] = x , f[*i] = f[*i] ^ (f[x] + si[*i]);ind[*i] -- ;if(!ind[*i]) q.push(*i);}}printf("%d\n%d\n" , ans.x , ans.y);
}
inline char nc()
{static char buf[100000] , *p1 , *p2;return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ;
}
inline int read()
{int ret = 0; char ch = nc();while(!isdigit(ch)) ch = nc();while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ '0') , ch = nc();return ret;
}
int main()
{int n = read() , m = read() , i , x , y;p = read();for(i = 1 ; i <= m ; i ++ ) x = read() , y = read() , e[x].push_back(y);for(i = 1 ; i <= n ; i ++ )if(!deep[i])tarjan(i);solve(n);return 0;
}
转载于:https://www.cnblogs.com/GXZlegend/p/7888921.html
【bzoj1093】[ZJOI2007]最大半连通子图 Tarjan+拓扑排序+dp相关推荐
- BZOJ 1093 [ZJOI2007]最大半连通子图
1093: [ZJOI2007]最大半连通子图 Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意 ...
- 解题报告:luogu P2272 [ZJOI2007]最大半连通子图(tarjan缩点、递推DP、hash、set判重)
这时yxc上课时讲解的截图. 一般用到tarjan算法的题目步骤都非常相似: tarjan算法 缩点,建图(这里要判重) 按照拓扑序递推(这里缩点以后逆向就已经是拓扑序了)/ 循环遍历新图求解答案. ...
- P2272-[ZJOI2007]最大半连通子图【tarjan,缩点】
正题 题目链接:https://www.luogu.com.cn/problem/P2272 题目大意 半连通图定义为任意两个点(u,v)(u,v)(u,v)满足uuu可以到vvv或vvv可以到uuu ...
- tyvj——P3524 最大半连通子图
P3524 最大半连通子图 时间: 3000ms / 空间: 165536KiB / Java类名: Main 描述 输入格式 第一行包含两个整数N,M,X.N,M分别表示图G的点数与边数,X的意义如 ...
- BZOJ 1093 ZJOI 2007 最大半连通子图 强联通分量+拓扑图DP
今天是放假的第一天(不说什么废话了) 什么是半连通子图?就是此图中包含的所有点两两点之间至少有一条单向路径. 题目问了两个问题 1.最大半连通子图的大小 2.最大半连通子图的个数 好了,这个问题看上去 ...
- 洛谷P1073 Tarjan + 拓扑排序 // 构造分层图
https://www.luogu.org/problemnew/show/P1073 C国有 n n个大城市和 mm 条道路,每条道路连接这 nn个城市中的某两个城市.任意两个城市之间最多只有一条道 ...
- 【BZOJ-1194】潘多拉的盒子 拓扑排序 + DP
1194: [HNOI2006]潘多拉的盒子 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 456 Solved: 215 [Submit][St ...
- [NOIP2017]逛公园 最短路+拓扑排序+dp
题目描述 给出一张 $n$ 个点 $m$ 条边的有向图,边权为非负整数.求满足路径长度小于等于 $1$ 到 $n$ 最短路 $+k$ 的 $1$ 到 $n$ 的路径条数模 $p$ ,如果有无数条则输出 ...
- 队爷的讲学计划(tarjan +拓扑排序)
题目描述 队爷为了造福社会,准备到各地去讲学.他的计划中有n个城市,从u到v可能有一条单向道路,通过这条道路所需费用为q.当队爷在u城市讲学完之后,u城市会派出一名使者与他同行,只要使者和他在一起,他 ...
- Wannafly挑战赛22 B 字符路径 ( 拓扑排序+dp )
链接:https://ac.nowcoder.com/acm/contest/160/B 来源:牛客网 题目描述 给一个含n个点m条边的有向无环图(允许重边,点用1到n的整数表示),每条边上有一个字符 ...
最新文章
- CE5.0 - romimage.exe如何填充eboot.bin中的pTOC特殊指针生成.nb0
- C#上位机软件串口数据接收用Invoke(同步)和BeginInvoke(异步)的区别
- 学习鸟哥的Linux私房菜笔记(1)——Linux系统入门
- RocketMQ-什么是死信队列?怎么解决
- linux下编译ios,为iOS安装OpenCV
- php 管理 mysql 数据库 代码_PHP5对Mysql5的任意数据库表的管理代码示例(三)
- php缩略图 实例,php生成缩略图后填充白边的代码示例
- 中文问题-Mobile-UrlEncode
- 语言中预算符号的优先级_Perl语言入门系列之一
- 2018年最新全国县级以上行政区划对应关系数据(按国家统计局网站整理)
- WINCE6.0+ILI9806E驱动IC显示屏调试总结
- 大数据技术体系(长期更新)
- 为什么要发布海外新闻稿,海外稿件怎么写
- 优酷 IPv6 演进和实践指南
- HoughCircles()函数 画圆心和圆的轮廓
- Intel MIC (至强融核) 安装步骤
- 视频拼接软件哪个好用?这些软件媒体人都喜欢
- 身份证最后一位出现“X”之原因
- 抽奖摇号系统随机性算法介绍
- WebJars简介 —— 前端资源的jar包形式