BZOJ 1093: [ZJOI2007]最大半连通子图 强连通分量缩点,最长链,拓扑排序,DP
来源:互联网 发布:播音录音软件 编辑:程序博客网 时间:2024/04/29 03:18
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
Sample Output
3
3
解题方法: Tarjan求scc,在缩点后的图跑拓排求最长链。在拓排树进行dp。拓排针对层级问题进行,先处理完了一个节点的前驱在处理该节点,除去了后效性,故可以在拓排树上dp。第一次知道拓排还可以这样用2333,dp[i]表示到i的最大半连通子图,sl[i]表示i这个强连通分量的点数,sum[i]表示方案数%k。
这里要注意,两点间可能有重边,要做判断防止一个点被加两遍。
代码如下:
#include <bits/stdc++.h>using namespace std;const int maxn = 100005;const int maxm = 2000005;int ind, cnt, scc, top, head1[maxn], head2[maxn];int dfn[maxn], low[maxn], hav[maxn], belong[maxn], q[maxn];bool inq[maxn];int n, m, X;int du[maxn], dp[maxn], sum[maxn], vis[maxn];//判断重边struct edge{int v, nxt; } E1[maxm], E2[maxm];int ans1, ans2;//answer1 answer2void init(){ memset(head1, -1, sizeof(head1)); memset(head2, -1, sizeof(head2)); cnt = 0;}void add1(int u, int v){ E1[cnt].v = v, E1[cnt].nxt = head1[u], head1[u]= cnt++;}void add2(int u, int v){ E2[cnt].v = v, E2[cnt].nxt = head2[u], head2[u] = cnt++; du[v]++;}void tarjian(int u){ //有向图的强连通分量缩点 dfn[u] = low[u] = ++ind; q[++top] = u; inq[u] = 1; for(int i = head1[u]; ~i; i = E1[i].nxt){ int v = E1[i].v; if(!dfn[v]) tarjian(v), low[u] = min(low[u], low[v]); else if(inq[v]) low[u] = min(low[u], dfn[v]); } int now = 0; if(low[u] == dfn[u]){ scc++; while(now != u){ now = q[top]; top--; inq[now] = 0; hav[scc]++; belong[now] = scc; } }}void rebuild(){ //重新建图 cnt = 0; for(int x = 1; x <= n; x++){ for(int i = head1[x]; ~i; i = E1[i].nxt){ if(belong[x] != belong[E1[i].v]){ add2(belong[x], belong[E1[i].v]); } } }}void topsort() //拓扑排序求最长链,递推记录方案{ queue <int> que; while(!que.empty()) que.pop(); for(int i = 1; i <= scc; i++){ if(!du[i]){ que.push(i); } dp[i] = hav[i]; sum[i] = 1; } while(!que.empty()){ int u = que.front(); que.pop(); for(int i = head2[u]; ~i; i = E2[i].nxt){ int v = E2[i].v; du[v]--; if(du[v] == 0) que.push(v); //if(v == u) continue; if(vis[v] == u) continue; if(dp[u] + hav[v] > dp[v]){ dp[v] = dp[u] + hav[v]; sum[v] = sum[u]; } else if(dp[u] + hav[v] == dp[v]){ sum[v] = (sum[v] + sum[u]) % X; } vis[v] = u; } }}int main(){ init(); scanf("%d%d%d", &n, &m, &X); for(int i = 1; i <= m; i++){ int u, v; scanf("%d%d", &u, &v); add1(u, v); } for(int i = 1; i <= n; i++) if(!dfn[i]) tarjian(i); rebuild(); topsort(); for(int i = 1; i <= scc; i++){ if(dp[i] > ans1) ans1 = dp[i], ans2 = sum[i]; else if(dp[i] == ans1){ ans2 = (ans2 + sum[i]) % X; } } cout << ans1 << endl; cout << ans2 << endl; return 0;}
- BZOJ 1093: [ZJOI2007]最大半连通子图 强连通分量缩点,最长链,拓扑排序,DP
- BZOJ 1093 最大半联通子图 强连通分量缩点+拓扑排序dp
- 【BZOJ1093】【ZJOI2007】最大半连通子图 强连通分量缩点+sort去重边+拓扑排序
- 【BZOJ 1093】【ZJOI 2007】【最大半连通子图】【tarjan强连通分量】【拓扑排序dp】
- [BZOJ]1093: [ZJOI2007]最大半连通子图 Tarjan缩点+拓扑图DP
- 【连通分量】BZOJ 1093: [ZJOI2007]最大半连通子图
- BZOJ 1093 ZJOI 2007 最大半连通子图 强联通分量+拓扑图DP
- BZOJ 1093 ZJOI 2007 最大半连通子图 强联通分量+拓扑图DP
- [BZOJ 1093][ZJOI2007]最大半连通子图(Tarjan+拓扑排序+Dp)
- [BZOJ1093][ZJOI2007]最大半连通子图 强联通+拓扑排序+dp 做题笔记
- BZOJ 1093: [ZJOI2007]最大半连通子图 拓扑图dp tarjan
- [BZOJ 1093 && YZOI1172] Tarjan缩点+拓扑DP 最大半连通子图
- BZOJ 1093 最大半连通子图(tarjan缩点 拓扑排序)
- 1093: [ZJOI2007]最大半连通子图 tarjan+拓扑最长链
- BZOJ 1093: [ZJOI2007]最大半连通子图
- BZOJ 1093: [ZJOI2007]最大半连通子图
- 【bzoj 1093】: [ZJOI2007]最大半连通子图
- 【BZOJ 1093】 [ZJOI2007]最大半连通子图
- atitit 图像处理机器视觉专业博硕连读课程表.xlsx
- atitit 图像处理 体系树 科技树 v4 r130a .xlsx
- 封装
- js中阻止a标签的跳转方法
- Android中Parcelable和Serializable区别
- BZOJ 1093: [ZJOI2007]最大半连通子图 强连通分量缩点,最长链,拓扑排序,DP
- 大家都说AI,我说说AI对成人产业的影响
- Hrbust 1836 2012世界末日【01背包+反路径输出】
- BigInteger找大素数
- 微信 聊天 机器人 python itchat
- Reflow(回流)
- POJ 1080 Human Gene Functions(LCS变形)
- 12.1.1
- pat-旧键盘打字