题目链接:https://vjudge.net/problem/UVA-11324
题意:求一个有向图中结点数最大的结点集,使得该结点集中任意两个结点u和v满足:要目u可以到达v,要么v可以到达u(相互可达也可以)。
思路:同一个强联通分量中满足结点集中任意两个结点u和v满足:要目u可以到达v,要么v可以到达u(相互可达也可以)。把强联通分量收缩点后得到scc图,让每个scc结点的权值等于他的结点数,则求scc图上权最大的路径。拓扑dp,也可以直接bfs,但是要建立一个新的起点,连接所有入度为0的结点。
代码:
#include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<map> #include<queue> #include<stack> #include<vector> using namespace std; typedef long long ll; const int MAXN=2e5+100,INF=0x3f3f3f3f,MOD=1e9+7; map<int,vector<int> >G; int pre[MAXN],lowlink[MAXN],sccno[MAXN],dfs_color,scc_cut; stack<int>S; map<int,vector<int> >NG; int deg[MAXN]; int in[MAXN]; void dfs(int u) { pre[u]=lowlink[u]=++dfs_color; S.push(u); for(int i=0; i<G[u].size(); i++) { int v=G[u][i]; if(!pre[v]) { dfs(v); lowlink[u]=min(lowlink[u],lowlink[v]); } else if(!sccno[v]) lowlink[u]=min(lowlink[u],lowlink[v]); } if(lowlink[u]==pre[u]) { scc_cut++; while(!S.empty()) { int x=S.top(); S.pop(); sccno[x]=scc_cut; deg[scc_cut]++; if(x==u) break; } } } void find_scc(int n) { dfs_color=scc_cut=0; memset(pre,0,sizeof(pre)); memset(sccno,0,sizeof(sccno)); memset(deg,0,sizeof(deg)); for(int i=1; i<=n; i++) if(!pre[i]) dfs(i); } void re_build(int n) { for(int i=1; i<=scc_cut; i++) in[i]=0,NG[i].clear(); for(int u=1; u<=n; u++) { for(int i=0; i<G[u].size(); i++) { int v=G[u][i]; if(sccno[u]==sccno[v]) continue; in[sccno[v]]++; NG[sccno[u]].push_back(sccno[v]); } } for(int i=1; i<=n; i++) G[i].clear(); } queue<int>q; int ans[MAXN]; void topsort() { memset(ans,0,sizeof(ans)); for(int i=1; i<=scc_cut; i++) if(in[i]==0) ans[i]=deg[i],q.push(i); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0; i<NG[u].size(); i++) { int v=NG[u][i]; ans[v]=max(ans[v],ans[u]+deg[v]); in[v]--; if(in[v]==0) q.push(v); } } } int main() { int T; scanf("%d",&T); while(T--) { int n,m; scanf("%d%d",&n,&m); for(int i=1; i<=m; i++) { int u,v; scanf("%d%d",&u,&v); G[u].push_back(v); } find_scc(n); re_build(n); topsort(); int Max=0; for(int i=1; i<=scc_cut; i++) Max=max(Max,ans[i]); cout<<Max<<endl; } return 0; }
tarjan缩点+拓扑dp
时间: 2024-10-24 19:23:24