题目描述

一个有向图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相关推荐

  1. BZOJ 1093 [ZJOI2007]最大半连通子图

    1093: [ZJOI2007]最大半连通子图 Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:?u,v∈V,满足u→v或v→u,即对于图中任意 ...

  2. 解题报告:luogu P2272 [ZJOI2007]最大半连通子图(tarjan缩点、递推DP、hash、set判重)

    这时yxc上课时讲解的截图. 一般用到tarjan算法的题目步骤都非常相似: tarjan算法 缩点,建图(这里要判重) 按照拓扑序递推(这里缩点以后逆向就已经是拓扑序了)/ 循环遍历新图求解答案. ...

  3. P2272-[ZJOI2007]最大半连通子图【tarjan,缩点】

    正题 题目链接:https://www.luogu.com.cn/problem/P2272 题目大意 半连通图定义为任意两个点(u,v)(u,v)(u,v)满足uuu可以到vvv或vvv可以到uuu ...

  4. tyvj——P3524 最大半连通子图

    P3524 最大半连通子图 时间: 3000ms / 空间: 165536KiB / Java类名: Main 描述 输入格式 第一行包含两个整数N,M,X.N,M分别表示图G的点数与边数,X的意义如 ...

  5. BZOJ 1093 ZJOI 2007 最大半连通子图 强联通分量+拓扑图DP

    今天是放假的第一天(不说什么废话了) 什么是半连通子图?就是此图中包含的所有点两两点之间至少有一条单向路径. 题目问了两个问题 1.最大半连通子图的大小 2.最大半连通子图的个数 好了,这个问题看上去 ...

  6. 洛谷P1073 Tarjan + 拓扑排序 // 构造分层图

    https://www.luogu.org/problemnew/show/P1073 C国有 n n个大城市和 mm 条道路,每条道路连接这 nn个城市中的某两个城市.任意两个城市之间最多只有一条道 ...

  7. 【BZOJ-1194】潘多拉的盒子 拓扑排序 + DP

    1194: [HNOI2006]潘多拉的盒子 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 456  Solved: 215 [Submit][St ...

  8. [NOIP2017]逛公园 最短路+拓扑排序+dp

    题目描述 给出一张 $n$ 个点 $m$ 条边的有向图,边权为非负整数.求满足路径长度小于等于 $1$ 到 $n$ 最短路 $+k$ 的 $1$ 到 $n$ 的路径条数模 $p$ ,如果有无数条则输出 ...

  9. 队爷的讲学计划(tarjan +拓扑排序)

    题目描述 队爷为了造福社会,准备到各地去讲学.他的计划中有n个城市,从u到v可能有一条单向道路,通过这条道路所需费用为q.当队爷在u城市讲学完之后,u城市会派出一名使者与他同行,只要使者和他在一起,他 ...

  10. Wannafly挑战赛22 B 字符路径 ( 拓扑排序+dp )

    链接:https://ac.nowcoder.com/acm/contest/160/B 来源:牛客网 题目描述 给一个含n个点m条边的有向无环图(允许重边,点用1到n的整数表示),每条边上有一个字符 ...

最新文章

  1. CE5.0 - romimage.exe如何填充eboot.bin中的pTOC特殊指针生成.nb0
  2. C#上位机软件串口数据接收用Invoke(同步)和BeginInvoke(异步)的区别
  3. 学习鸟哥的Linux私房菜笔记(1)——Linux系统入门
  4. RocketMQ-什么是死信队列?怎么解决
  5. linux下编译ios,为iOS安装OpenCV
  6. php 管理 mysql 数据库 代码_PHP5对Mysql5的任意数据库表的管理代码示例(三)
  7. php缩略图 实例,php生成缩略图后填充白边的代码示例
  8. 中文问题-Mobile-UrlEncode
  9. 语言中预算符号的优先级_Perl语言入门系列之一
  10. 2018年最新全国县级以上行政区划对应关系数据(按国家统计局网站整理)
  11. WINCE6.0+ILI9806E驱动IC显示屏调试总结
  12. 大数据技术体系(长期更新)
  13. 为什么要发布海外新闻稿,海外稿件怎么写
  14. 优酷 IPv6 演进和实践指南
  15. HoughCircles()函数 画圆心和圆的轮廓
  16. Intel MIC (至强融核) 安装步骤
  17. 视频拼接软件哪个好用?这些软件媒体人都喜欢
  18. 身份证最后一位出现“X”之原因
  19. 抽奖摇号系统随机性算法介绍
  20. WebJars简介 —— 前端资源的jar包形式

热门文章

  1. 阿里人告诉你毕业3年,为何技术能力相差越来越大?
  2. 今日头条首次公开算法原理(附全文详解)
  3. BAT等大厂十年研发经历,总结了12开发条经验(墙裂推荐)
  4. 开源巨献:腾讯最热门30款开源项目
  5. 各位学Python的要小心了!!!
  6. python三次方函数_python函数基础------第三次作业讲解(二)
  7. form表单居中_HTML基本结构、命名及对表单专项练习解释
  8. python3-基础8
  9. Android 6.0 动态权限申请注意事项
  10. 由swap引出的局部变量,形参和指针的小问题