ZOJ Problem Set - 3795(缩点拓补)
来源:互联网 发布:linux系统dd命令 编辑:程序博客网 时间:2024/05/01 01:18
题意:每条信息说明了两个一定不在一个集合里的人,求最少情况集合可以划分为多少子集。
一看就是拓补树的最高层数,但题意中隐含了可能有环(>=关系偏序),所以要先缩点,再拓补。当然,缩点之后图中没有环,直接dfs记忆化也是ok的。
代码:
#include<iostream>#include<cstdio>#include<cmath>#include<map>#include<queue>#include<vector>#include<cstring>#include<algorithm>#define rep(i,a,b) for(int i=(a);i<(b);i++)#define rev(i,a,b) for(int i=(a);i>=(b);i--)#define clr(a,x) memset(a,x,sizeof a)#define INF 0x3f3f3f3ftypedef long long LL;using namespace std;const int maxn=100005;const int maxm=300005;int first[maxn],ecnt,u[maxm],v[maxm],nex[maxm];int low[maxn],dfn[maxn],stck[maxn],belong[maxn];int indx,top,scc;bool ins[maxn];int num[maxn];int in[maxn],out[maxn];int h[maxn];int n,m;int ecntt,firstt[maxn],uu[maxm],vv[maxm],nexx[maxm];void tarjan(int u){ low[u]=dfn[u]=++indx; stck[top++]=u; ins[u]=1; for(int e=first[u];~e;e=nex[e]) { if(!dfn[v[e]]) { tarjan(v[e]); low[u]=min(low[u],low[v[e]]); } else if(ins[v[e]])low[u]=min(low[u],dfn[v[e]]); } if(low[u]==dfn[u]) { int v; scc++; do { v=stck[--top]; ins[v]=false; belong[v]=scc; num[scc]++; }while(v!=u); }}void solve(int n){ clr(dfn,0); clr(ins,0); clr(num,0); indx=scc=top=0; for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i);}void add_(int a,int b){ u[ecnt]=a; v[ecnt]=b; nex[ecnt]=first[a]; first[a]=ecnt++;}void add__(int a,int b){ uu[ecntt]=a; vv[ecntt]=b; nexx[ecntt]=firstt[a]; firstt[a]=ecntt++;}void init(){ ecnt=0; clr(first,-1);}bool topsort(int n,int first[],int v[],int nex[]){ queue<int>q; memset(h,0,sizeof h); for(int i=1;i<=n;i++) if(!in[i])q.push(i),h[i]=num[i]; int cur=0; while(!q.empty()) { int x=q.front();q.pop(); cur++; for(int e=first[x];~e;e=nex[e]) if(v[e]!=-1){ h[v[e]]=max(h[v[e]],h[x]+num[v[e]]); if(--in[v[e]]==0)q.push(v[e]); } } return cur==n;}int dfs(int root){ if(h[root])return h[root]; h[root]=num[root]; for(int e=firstt[root];~e;e=nexx[e]) { dfs(vv[e]); h[root]=max(h[root],h[vv[e]]+num[root]); } return h[root];}int gettop(int n){ clr(h,0); int ans=1; for(int i=1;i<=n;i++) if(!in[i]) { ans=max(ans,dfs(i)); } return ans;}void suodian(){ ecntt=0;clr(firstt,-1); clr(in,0); for(int e=0;e<ecnt;e++) { int a=belong[u[e]]; int b=belong[v[e]]; if(a!=b)add__(a,b),in[b]++; }}int main(){ int a,b; while(~scanf("%d%d",&n,&m)) { init(); for(int i=0;i<m;i++) { scanf("%d%d",&a,&b); add_(a,b); } solve(n); suodian(); topsort(scc,firstt,vv,nexx); int ans=1; for(int i=1;i<=scc;i++) ans=max(ans,h[i]); /*int ans=gettop(scc);*/ printf("%d\n",ans); } return 0;}
0 0
- ZOJ Problem Set - 3795(缩点拓补)
- ZOJ Problem Set - 2060
- ZOJ Problem Set - 2972
- ZOJ Problem Set - 1037
- ZOJ Problem Set - 1048
- ZOJ Problem Set - 1049
- ZOJ Problem Set - 1051
- ZOJ Problem Set - 1067
- ZOJ Problem Set - 1115
- ZOJ Problem Set - 1151
- ZOJ Problem Set - 1205
- ZOJ Problem Set - 1025
- ZOJ Problem Set - 1029
- ZOJ Problem Set - 1076
- ZOJ Problem Set - 1117
- ZOJ Problem Set - 1041
- ZOJ Problem Set - 1004
- ZOJ Problem Set - 1005
- 推荐一些C#相关的网站、资源和书籍
- c#创建类似Siri的语音问答的简单应用
- lr:项目 性能测试中的数据解释与分析
- 上海合成树脂瓦--红波
- Sublime Text 3 快捷键
- ZOJ Problem Set - 3795(缩点拓补)
- Linux命令汇总之a.*
- python socket编程练习
- python excel文件操作
- hdu 1009 FatMouse' Trade(贪心)
- Jsoup入门-java
- Codeforces Round #280 (Div. 2) D
- windows更改没人格林威治时间命令
- asp.net 生成、解析条形码和二维码