【bzoj1093】【tarjan+dp】最大半联通子图
2016-12-26 22:08
337 查看
题意
导出子图:对图(U,V),有(U′,V′)满足 U′∈U V’是V中所有与U’相连的边
半连通子图:对图(U,V),对任意u∈U v∈U满足u到v或 v 到u 有一条有向路径
题解
首先考虑对于一个强连通分量一定是一个半连通导出子图,考虑缩点,对于缩点之后的DAG,在一条链上的强连通分量就为一个半联通子图,问题转化成求DAG最长链,考虑按拓扑序dp,记l[]为到该点的最长路径,记cnt[]为方案数,对于每个入度为0的点向其连通的点扩展
l[to]=l[u]+size[to](l[to]<l[u]+size[to])
cnt[to]+=cnt[u]
注
这题需要注意缩点之后的重边问题,记录vis为前驱标记,或者建图时优化。
导出子图:对图(U,V),有(U′,V′)满足 U′∈U V’是V中所有与U’相连的边
半连通子图:对图(U,V),对任意u∈U v∈U满足u到v或 v 到u 有一条有向路径
题解
首先考虑对于一个强连通分量一定是一个半连通导出子图,考虑缩点,对于缩点之后的DAG,在一条链上的强连通分量就为一个半联通子图,问题转化成求DAG最长链,考虑按拓扑序dp,记l[]为到该点的最长路径,记cnt[]为方案数,对于每个入度为0的点向其连通的点扩展
l[to]=l[u]+size[to](l[to]<l[u]+size[to])
cnt[to]+=cnt[u]
注
这题需要注意缩点之后的重边问题,记录vis为前驱标记,或者建图时优化。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <queue> #define MAXN 100001 using namespace std; struct edge{ int to; edge *nxt; edge(){} edge(int a):to(a),nxt(NULL){} }; struct li{ edge *pre,*lst; void push(int a){ if(!pre) pre=lst=new edge(a); else lst=lst->nxt=new edge(a); } }e[MAXN],t[MAXN]; int n,m,X; int bel[MAXN],dfn[MAXN],size[MAXN],low[MAXN],sta[MAXN],top,in[MAXN],P,T; void tarjan(int u){ dfn[u]=low[u]=++T;sta[++top]=u; for(edge *it=e[u].pre;it;it=it->nxt){ if(in[it->to]) continue; if(!dfn[it->to]) tarjan(it->to); low[u]=min(low[u],low[it->to]); } if(low[u]==dfn[u]){ int v;P++; do{ size[P]++; bel[v=sta[top--]]=P;in[v]=1; }while(u!=v); } } int l[MAXN],cnt[MAXN],ind[MAXN]; int vis[MAXN]; queue<int> q; void Sort(){ memset(in,0,sizeof in); for(int i=1;i<=P;i++) if(ind[i]==0) l[i]=size[i],cnt[i]=1,q.push(i),in[i]=1; while(!q.empty()){ int u=q.front();q.pop(); for(edge *it=t[u].pre;it;it=it->nxt){ if(ind[it->to]&&!in[it->to]){ ind[it->to]--; if(ind[it->to]==0) q.push(it->to),in[it->to]=1; if(vis[it->to]==u) continue; if(l[u]+size[it->to]>l[it->to]){ l[it->to]=l[u]+size[it->to]; cnt[it->to]=cnt[u]; } else if(l[u]+size[it->to]==l[it->to]) cnt[it->to]=(cnt[it->to]+cnt[u])%X; vis[it->to]=u; } } } } int main(){ scanf("%d%d%d",&n,&m,&X); for(int i=1;i<=m;i++){ int a,b; scanf("%d%d",&a,&b); e[a].push(b); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++) for(edge *it=e[i].pre;it;it=it->nxt) if(bel[i]!=bel[it->to]) t[bel[i]].push(bel[it->to]),ind[bel[it->to]]++; Sort(); int maxx=0,ans=0; for(int i=1;i<=P;i++) maxx=max(maxx,l[i]); for(int i=1;i<=P;i++) if(l[i]==maxx) (ans+=cnt[i])%=X; printf("%d\n%d\n",maxx,ans); return 0; }
相关文章推荐
- [BZOJ1093][ZJOI2007][Tarjan][DP]最大半联通子图
- 【BZOJ1093】【ZJOI2007】最大半联通子图 [DP][Tarjan]
- BZOJ 1093 ZJOI 2007 最大半连通子图 强联通分量+拓扑图DP
- [BZOJ1093]ZJOI2007最大半联通子图|强联通分量|DP
- [bzoj 1093][ZJOI2007]最大半联通子图(强联通缩点+DP)
- 【bzoj1093】【zjoi2007】【最大半联通子图】【缩点+dp】
- [BZOJ]1093: [ZJOI2007]最大半连通子图 Tarjan缩点+拓扑图DP
- BZOJ 1093: [ZJOI2007]最大半连通子图( tarjan + dp )
- BZOJ 1093 [ZJOI 2007] 最大半连通子图 (tarjan+树形DP)
- [BZOJ 1093 && YZOI1172] Tarjan缩点+拓扑DP 最大半连通子图
- [bzoj1093][ZJOI2007]最大半连通子图 Tarjan,DP
- BZOJ 1093 ZJOI 2007 最大半连通子图 强联通分量+拓扑图DP
- BZOJ 1093 [ZJOI2007] 最大半连通子图(强联通缩点+DP)
- bzoj 1093 最大半连通子图 - Tarjan - 拓扑排序 - 动态规划
- BZOJ 1093 最大半连通子图(强连通分量+树形DP)
- [题解]bzoj1093(ZJOI2007)最大半联通子图
- BZOJ 1093 ZJOI 2007 最大半连通子图 DP
- [BZOJ1093][ZJOI2007]最大半连通子图 强联通+拓扑排序+dp 做题笔记
- BZOJ 1093: [ZJOI2007]最大半连通子图 强连通分量缩点,最长链,拓扑排序,DP
- BZOJ1093 [ZJOI2007]最大半连通子图 【tarjan缩点 + DAG最长路计数】