[BZOJ1093][ZJOI2007]最大半连通子图
Posted Elder_Giang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1093][ZJOI2007]最大半连通子图相关的知识,希望对你有一定的参考价值。
1093: [ZJOI2007]最大半连通子图
Time Limit: 30 Sec Memory Limit: 162 MB Submit: 3710 Solved: 1464 [Submit][Status][Discuss]Description
一个有向图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 ≤1 00000, 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
1 2
2 1
1 3
2 4
5 6
6 4
Sample Output
3
3
3
缩点后求DAG上最长链(点权)以及最长链的方案数
注意判重边
#include <cstdio> #include <algorithm> using namespace std; const int maxn = 100000 + 10, maxm = 1000000 + 10; int n, m, mod; struct Edge{ int to, next; Edge(){} Edge(int _t, int _n): to(_t), next(_n){} }e[maxm * 2]; int fir[maxn * 2] = {0}, cnt = 0; inline void add(int u, int v){ e[++cnt] = Edge(v, fir[u]); fir[u] = cnt; } int belong[maxn], siz[maxn * 2] = {0}, bcnt = 0; int dfn[maxn], low[maxn], index = 0; int sta[maxn], top = 0; bool ins[maxn] = {false}; void tarjan(int u){ ins[u] = true; sta[++top] = u; dfn[u] = low[u] = ++index; for(int v, i = fir[u]; i; i = e[i].next){ v = e[i].to; if(!dfn[v]){ tarjan(v); low[u] = min(low[u], low[v]); } else if(ins[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]){ int now; bcnt++; do{ now = sta[top--]; ins[now] = false; belong[now] = bcnt; siz[bcnt]++; }while(now != u); } } int ind[maxn * 2] = {0}, q[maxn], h, t; void tsort(){ for(int v, u = 1; u <= n; u++) for(int i = fir[u]; i; i = e[i].next){ v = e[i].to; if(belong[v] != belong[u]){ ind[belong[v]]++; add(belong[u], belong[v]); } } h = t = 0; for(int i = n + 1; i <= bcnt; i++) if(!ind[i]) q[t++] = i; int u, v; while(h != t){ u = q[h++]; for(int i = fir[u]; i; i = e[i].next){ v = e[i].to; ind[v]--; if(!ind[v]) q[t++] = v; } } } int f[maxn * 2], g[maxn * 2]; int mark[maxn * 2] = {0}; void dp(){ int u, v; for(int i = h; ~i; i--){ u = q[i]; f[u] = siz[u]; g[u] = 1; for(int j = fir[u]; j; j = e[j].next){ v = e[j].to; if(mark[v] == u) continue; mark[v] = u; if(f[v] + siz[u] > f[u]){ f[u] = f[v] + siz[u]; g[u] = g[v]; } else if(f[v] + siz[u] == f[u]) g[u] = (g[u] + g[v]) % mod; } } } int main(){ scanf("%d %d %d", &n, &m, &mod); for(int u, v, i = 1; i <= m; i++){ scanf("%d %d", &u, &v); add(u, v); } bcnt = n; for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i); tsort(); dp(); int ans = 0, sum = 0; for(int i = n + 1; i <= bcnt; i++){ if(f[i] > ans){ ans = f[i]; sum = g[i]; } else if(f[i] == ans) sum = (sum + g[i]) % mod; } printf("%d\n%d\n", ans, sum); return 0; }
以上是关于[BZOJ1093][ZJOI2007]最大半连通子图的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1093: [ZJOI2007]最大半连通子图tarjan+拓扑排序+dp