首页 > 代码库 > 【强连通分量缩点】【拓扑排序】【dp预处理】CDOJ1640 花自飘零水自流,一种相思,两处闲愁。
【强连通分量缩点】【拓扑排序】【dp预处理】CDOJ1640 花自飘零水自流,一种相思,两处闲愁。
题意: 在n个点m条边的有向图上,从1出发的回路最多经过多少个不同的点 可以在一条边上逆行一次
题解: 在同一个强连通分量中,显然可以经过当中的每一个点 因此先将强连通分量缩点,点权为强连通分量的点数
如果不逆行,那么答案就是1所在的强连通分量的点数 如果逆行了,那么逆行的边必然在缩点后的拓扑图上
假设逆行的边为u->v,那么该回路可分为1到v和u到1两部分 经过的最多点数即1到v与u到1路径上的最大点权和减去1的点权 (这里的点指的都是缩点后的点)
例子中在边4->3上逆行就能从1出发经过所有点回到1
那么预处理拓扑图上1到每个点的最大点权和及每个点到1的最大点权和(将边倒过来搞一次就行) 枚举逆行的边即可得到答案。
#include<cstdio> #include<cstring> #include<queue> #include<algorithm> #include<vector> using namespace std; typedef long long ll; vector<int>G[100010],rG[100010],vs; bool used[100010]; int cmp[100010],x[100010],y[100010],a[100010],f[100010],g[100010],ru[100010],ru2[100010]; int n,m,K; void dfs(int U){ used[U]=1; for(int i=0;i<G[U].size();++i){ if(!used[G[U][i]]){ dfs(G[U][i]); } } vs.push_back(U); } void rdfs(int U){ used[U]=1; cmp[U]=K; for(int i=0;i<rG[U].size();++i){ if(!used[rG[U][i]]){ rdfs(rG[U][i]); } } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;++i){ scanf("%d%d",&x[i],&y[i]); G[x[i]].push_back(y[i]); rG[y[i]].push_back(x[i]); } for(int i=1;i<=n;++i){ if(!used[i]){ dfs(i); } } memset(used,0,sizeof(used)); for(int i=vs.size()-1;i>=0;--i){ if(!used[vs[i]]){ ++K; rdfs(vs[i]); } } for(int i=1;i<=n;++i){ G[i].clear(); rG[i].clear(); } for(int i=1;i<=m;++i){ if(cmp[x[i]]!=cmp[y[i]]){ G[cmp[x[i]]].push_back(cmp[y[i]]); ++ru[cmp[y[i]]]; rG[cmp[y[i]]].push_back(cmp[x[i]]); ++ru2[cmp[x[i]]]; } } for(int i=1;i<=n;++i){ ++a[cmp[i]]; } queue<int>q; for(int i=1;i<=K;++i){ if(!ru[i]){ q.push(i); } } memset(f,0xaf,sizeof(f)); f[cmp[1]]=a[cmp[1]]; while(!q.empty()){ int U=q.front(); q.pop(); for(int i=0;i<G[U].size();++i){ f[G[U][i]]=max(f[G[U][i]],f[U]+a[G[U][i]]); --ru[G[U][i]]; if(!ru[G[U][i]]){ q.push(G[U][i]); } } } for(int i=1;i<=K;++i){ if(!ru2[i]){ q.push(i); } } memset(g,0xaf,sizeof(g)); g[cmp[1]]=a[cmp[1]]; while(!q.empty()){ int U=q.front(); q.pop(); for(int i=0;i<rG[U].size();++i){ g[rG[U][i]]=max(g[rG[U][i]],g[U]+a[rG[U][i]]); --ru2[rG[U][i]]; if(!ru2[rG[U][i]]){ q.push(rG[U][i]); } } } int ans=a[cmp[1]]; for(int i=1;i<=m;++i){ if(cmp[x[i]]!=cmp[y[i]]){ ans=(int)max((ll)ans,(ll)f[cmp[y[i]]]+(ll)g[cmp[x[i]]]-(ll)a[cmp[1]]); } } printf("%d\n",ans); return 0; }
【强连通分量缩点】【拓扑排序】【dp预处理】CDOJ1640 花自飘零水自流,一种相思,两处闲愁。
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。