BZOJ 1093 浅谈tarjan缩点DAG最长路径即拓扑排序
2017-07-10 15:49
393 查看
(这次的图是自己画的2333)
世界真的很大
这道题有点扯,思路不太好想
关键是想清楚半连通分量的等价类
然后就好办了
有一些坑点
先看一下题吧
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
第一行包含3个整数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.
首先应该明确半连通分量是个什么东西
有向图,分量,自然先想到强连通分量
如果点u到达点v,点v不到达点u,点v所在的强连通分量u也全部可以到达,而全部不能到达v
如果能的话u和v就在一个强连通分量里了2333
即半连通分量就是强连通分量缩点后的一条链
即求缩点后的图里的最长链
可以看一下这篇
大体来说采用拓扑排序的思路
用bfs的方法更新状态
有个坑点就是两个强连通分量缩点后的点之间有可能不止一条边,可能会导致重复更新
对每一个点记录一下现在的点是由哪一个点更新来的,避免重复
没什么了
完整代码:
#include<stdio.h> #include<stack> #include<queue> #include<cstring> using namespace std; struct edge { int last,v,u; }ed[2000010],ad[2000010]; stack <int> stk; queue <int> state; int head[200010],place[200010],vis[200010],ins[200010]; int dfn[200010],low[200010],siz[200010],in[200010]; int dis[200010],nmb[200010]; int num=0,cnt=0,idx=0,mum=0,ans=0,bns=0,n,m,mod,tar; void add(int u,int v) { num++; ed[num].v=v; ed[num].u=u; ed[num].last=head[u]; head[u]=num; } void ade(int u,int v) { mum++; ad[mum].v=v; ad[mum].last=head[u]; head[u]=mum; } void tarjan(int u) { dfn[u]=low[u]=++idx; vis[u]=ins[u]=1; stk.push(u); for(int i=head[u];i;i=ed[i].last) { int v=ed[i].v; if(!vis[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(ins[v]) { low[u]=min(low[u],dfn[v]); } } if(dfn[u]==low[u]) { cnt++;int t=-1; while(t!=u) { t=stk.top(); place[t]=cnt; siz[cnt]++; ins[t]=0; stk.pop(); } } } void rebuild() { memset(head,0,sizeof(head)); for(int i=1;i<=num;i++) if(place[ed[i].u]!=place[ed[i].v]) { ade(place[ed[i].u],place[ed[i].v]); in[place[ed[i].v]]++; } } void top() { memset(vis,0,sizeof(vis)); for(int i=1;i<=cnt;i++) if(in[i]==0) { state.push(i); dis[i]=siz[i];nmb[i]=1; } while(!state.empty()) { int u=state.front(); state.pop(); for(int i=head[u];i;i=ad[i].last) { int v=ad[i].v; in[v]--; if(in[v]==0) state.push(v); if(vis[v]==u) continue ; if(dis[v]<dis[u]+siz[v]) { dis[v]=dis[u]+siz[v]; nmb[v]=nmb[u]; } else if(dis[v]==dis[u]+siz[v]) nmb[v]=(nmb[u]+nmb[v])%mod; vis[v]=u; } } for(int i=1;i<=cnt;i++) if(dis[i]>ans) ans=dis[i]; for(int i=1;i<=cnt;i++) if(dis[i]==ans) bns=(bns+nmb[i])%mod; } int main() { scanf("%d%d%d",&n,&m,&mod); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); } for(int i=1;i<=n;i++) if(!vis[i]) tarjan(i); rebuild(); top(); printf("%d\n%d",ans,bns%mod); return 0; }
嗯,就是这样
相关文章推荐
- BZOJ 1093 最大半连通子图(tarjan缩点 拓扑排序)
- 【BZOJ1179】atm,tarjan缩点+最长路径
- 20161026的考试】KMP,二维LIS,DAG删一个点求最长路径最小值(BZOJ 3832)
- bzoj 1093 最大半连通子图 - Tarjan - 拓扑排序 - 动态规划
- 【BZOJ-1924】所驼门王的宝藏 Tarjan缩点(+拓扑排序) + 拓扑图DP
- BZOJ2427 浅谈TARJAN缩点 和 树形依赖背包动态规划
- [BZOJ]1093: [ZJOI2007]最大半连通子图 Tarjan缩点+拓扑图DP
- BZOJ 1093: [ZJOI2007]最大半连通子图 强连通分量缩点,最长链,拓扑排序,DP
- [BZOJ 1093 && YZOI1172] Tarjan缩点+拓扑DP 最大半连通子图
- BZOJ 2150 浅谈二分图Bipartite Graph及DAG最小路径覆盖
- BZOJ1093 [ZJOI2007]最大半连通子图 【tarjan缩点 + DAG最长路计数】
- 浅谈Tarjan缩点(分析+模板)
- BZOJ 2208 [Jsoi2010]连通数 tarjan缩点+bitset优化DP
- bzoj2893 征服王(tarjan缩点+有上下界最小流/费用流)
- 【BZOJ1051】受欢迎的牛,tarjan缩点重构图
- hdu 3861(tarjan 缩点 + 二分图匹配 求最小路径覆盖
- 【bzoj1179】[Apio2009]Atm Tarjan缩点+Spfa最长路
- 【强联通分量缩点】【Tarjan】bzoj1051 [HAOI2006]受欢迎的牛
- ZOJ 3206 (tarjan缩点+DAG带权最长路)
- bzoj1179: [Apio2009]Atm 【缩点+spfa最长路】