bzoj 1093 最大半连通子图 - Tarjan - 拓扑排序 - 动态规划
一个有向图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的余数。
Input
第一行包含两个整数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
Output
应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.
Sample Input
6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4
Sample Output
3
3
题目大意 一个有向图G(V, U)是半连通的,当且仅当任意点
,并且存在一条路径,它上面的所有边属于U,并且从u到v或者从v到u。图G的导出子图G‘(V'. U'),满足
.一个有向图G的半连通子图是一个导出子图且半连通,最大半连通子图是其中拥有最多点数的半连通子图。问最大的半连通子图的点数和数量。
因为半连通子图一定是导出子图,所以两个半连通子图是否同构之和它们的定点集合有关。
由于图上可能有环(强连通分量),所以考虑缩点。缩点后的图是个DAG,然后你可得到一个结论就是这个DAG上的一条路径就是原图的一个半连通子图,并且DAG上的路径和原图中的半连通子图一一对应。
我们可以赋予每个点一个点权,代表它在原图中代表的点数。
于是这个问题转换成在DAG上最长路及其计数。这个拓扑排序再加个小dp就可以水过了。
另外注意拓扑排序的时判断重边。
Code
/**
* bzoj
* Problem#1093
* Accepted
* Time: 1988ms
* Memory: 13740k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean;
#define smin(a, b) a = min(a, b)
#define smax(a, b) b = max(a, b) int n, m;
int moder;
vector<int> *g; inline void init() {
scanf("%d%d%d", &n, &m, &moder);
g = new vector<int>[(n + )];
for(int i = , u, v; i <= m; i++) {
scanf("%d%d", &u, &v);
g[u].push_back(v);
}
} int cnt = ;
stack<int> s;
int* visitID;
int* exitID;
int* belong;
boolean *visited;
boolean *instack;
inline void init_tarjan() {
visitID = new int[(n + )];
exitID = new int[(n + )];
visited = new boolean[(n + )];
instack = new boolean[(n + )];
belong = new int[(n + )];
memset(visited, false, sizeof(boolean) * (n + ));
memset(instack, false, sizeof(boolean) * (n + ));
} void tarjan(int node) {
visitID[node] = exitID[node] = ++cnt;
visited[node] = instack[node] = true;
s.push(node); for(int i = ; i < (signed)g[node].size(); i++) {
int& e = g[node][i];
if(!visited[e]) {
tarjan(e);
smin(exitID[node], exitID[e]);
} else if(instack[e]) {
smin(exitID[node], visitID[e]);
}
} if(visitID[node] == exitID[node]) {
int e;
do {
e = s.top();
s.pop();
instack[e] = false;
belong[e] = node;
} while(e != node);
}
} vector<int> *ng;
int* dag;
int *val;
inline void rebuild() {
dag = new int[(n + )];
ng = new vector<int>[(n + )];
val = new int[(n + )];
memset(val, , sizeof(int) * (n + ));
memset(dag, , sizeof(int) * (n + )); for(int i = ; i <= n; i++)
for(int j = ; j < (signed)g[i].size(); j++) {
int& e = g[i][j];
if(belong[e] != belong[i])
ng[belong[i]].push_back(belong[e]), dag[belong[e]]++;
} for(int i = ; i <= n; i++)
val[belong[i]]++;
} queue<int> que;
int *dis;
int *counter;
inline void topu() {
dis = new int[(n + )];
counter = new int[(n + )];
memset(dis, , sizeof(int) * (n + ));
memset(visited, false, sizeof(boolean) * (n + )); for(int i = ; i <= n; i++)
if(belong[i] == i && !dag[i])
que.push(i), dis[i] = val[i], counter[i] = ; while(!que.empty()) {
int e = que.front();
que.pop();
for(int i = ; i < (signed)ng[e].size(); i++) {
int& eu = ng[e][i];
dag[eu]--;
if(!dag[eu])
que.push(eu);
if(visited[eu]) continue;
visited[eu] = true; if(dis[e] + val[eu] > dis[eu]) {
dis[eu] = dis[e] + val[eu];
counter[eu] = counter[e];
} else if(dis[e] + val[eu] == dis[eu])
counter[eu] = (counter[eu] + counter[e]) % moder;
}
for(int i = ; i < (signed)ng[e].size(); i++)
visited[ng[e][i]] = false;
}
} int maxdis = -, res = ;
inline void solve() {
for(int i = ; i <= n; i++) {
if(belong[i] != i) continue;
if(dis[i] > maxdis) {
maxdis = dis[i];
res = counter[i];
} else if(dis[i] == maxdis)
(res += counter[i]) %= moder;
}
printf("%d\n%d", maxdis, res);
} int main() {
init();
init_tarjan();
for(int i = ; i <= n; i++)
if(!visited[i])
tarjan(i);
rebuild();
topu();
solve();
return ;
}
bzoj 1093 最大半连通子图 - Tarjan - 拓扑排序 - 动态规划的更多相关文章
- 【bzoj1093】[ZJOI2007]最大半连通子图 Tarjan+拓扑排序+dp
题目描述 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:对于u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v的有向路径或者从v到u的有向路径. ...
- BZOJ 1093 最大半连通子图 题解
1093: [ZJOI2007]最大半连通子图 Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 2767 Solved: 1095[Submit][S ...
- [BZOJ]1093 最大半连通子图(ZJOI2007)
挺有意思的一道图论. Description 一个有向图G=(V,E)称为半连通的(Semi-Connected),如果满足:∀u,v∈V,满足u→v或v→u,即对于图中任意两点u,v,存在一条u到v ...
- BZOJ 1093 最大半连通子图
缩点求最长链. #include<iostream> #include<cstdio> #include<cstring> #include<algorith ...
- BZOJ 1093: [ZJOI2007]最大半连通子图( tarjan + dp )
WA了好多次... 先tarjan缩点, 然后题意就是求DAG上的一条最长链. dp(u) = max{dp(v)} + totu, edge(u,v)存在. totu是scc(u)的结点数. 其实就 ...
- [luogu2272 ZJOI2007] 最大半连通子图 (tarjan缩点 拓扑排序 dp)
传送门 题目描述 一个有向图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' ...
- Luogu P2272 [ZJOI2007]最大半连通子图(Tarjan+dp)
P2272 [ZJOI2007]最大半连通子图 题意 题目描述 一个有向图\(G=(V,E)\)称为半连通的\((Semi-Connected)\),如果满足:\(\forall u,v\in V\) ...
- [ZJOI2007]最大半连通子图 (Tarjan缩点,拓扑排序,DP)
题目链接 Solution 大概是个裸题. 可以考虑到,如果原图是一个有向无环图,那么其最大半联通子图就是最长的一条路. 于是直接 \(Tarjan\) 缩完点之后跑拓扑序 DP就好了. 同时由于是拓 ...
随机推荐
- Unittest + python
Unittest简单应用 #_*_coding:utf8_*_ import unittest from selenium import webdriver import time class Tes ...
- spring之文件上传
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...
- PHP与JSP简单比较
比较PHP和JSP这两个Web开发技术,在目前的情况是其实是比较php和Java的Web开发.以下就几个主要方面进行的比较: 一. 语言比较 PHP是解释执行的服务器脚本语言,首先php有简单容易上手 ...
- net npoi将List<实体>导出excel的最简单方法
只是临时导数据用的.方便.最基本的方法, [HttpGet] [Route("ExportEnterprise")] public BaseResponse ExportEnter ...
- c#之如何转换文本文件编码格式为utf-8
如代码: string content = File.ReadAllText(path, Encoding.Default); File.WriteAllText(path, content, Enc ...
- N-城堡问题
1 2 3 4 5 6 7 ############################# 1 # | # | # | | # #####---#####---#---#####---# 2 # # | ...
- 4.无监督学习--K-means聚类
K-means方法及其应用 1.K-means聚类算法简介: k-means算法以k为参数,把n个对象分成k个簇,使簇内具有较高的相似度,而簇间的相似度较低.主要处理过程包括: 1.随机选择k个点作为 ...
- JOptionPane
2018-10-30 14:44:43 开始写 作者:tjk123456 来源:CSDN 原文链接 建议阅读官方资料:https://docs.oracle.com/javase/7/docs/api ...
- 【转】win中IDLE选择virtualenv的启动方法
从dos命令行运行.(virtualenv dir)\Scripts\activate.bat脚本激活环境,然后执行: python -m idlelib.idle 摘录:https://blog.c ...
- uva 10600 ACM Contest And Blackout
题意: 求最小生成树和次小生成树的总权值. 思路: 第一种做法,适用于规模较小的时候,prim算法进行的时候维护在树中两点之间路径中边的最大值,复杂度O(n^2),枚举边O(m),总复杂度O(n^2) ...