题意:
给一张有向图G,求一个结点数最大的结点集,使得该结点中任意两个结点 u 和 v满足:要么 u 可以到达 v, 要么 v 可以到达 u(u 和 v 相互可达也可以)。
分析:
Tarjan求SCC缩点,SCC的节点数为新点点权,然后求DAG上权最大的的路径。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #define Maxn 1010 5 #define Maxm 50010 6 7 struct node 8 { 9 int x,y,next; 10 }t[Maxm]; 11 12 int first[Maxn],dfn[Maxn],low[Maxn],sta[Maxn],scc[Maxn],sum[Maxn]; 13 bool bj[Maxn],bj2[Maxn],map[Maxn][Maxn]; 14 int cnt,sl,cl; 15 16 int mymin(int x,int y) {return x<y?x:y;} 17 int mymax(int x,int y) {return x>y?x:y;} 18 19 void ffind(int x) 20 { 21 dfn[x]=low[x]=++cnt; 22 sta[++sl]=x; 23 for(int i=first[x];i;i=t[i].next) 24 { 25 int y=t[i].y; 26 if(dfn[y]==0) 27 { 28 ffind(y); 29 low[x]=mymin(low[x],low[y]); 30 } 31 else if(scc[y]==0) low[x]=mymin(low[x],dfn[y]); 32 } 33 if(dfn[x]==low[x]) 34 { 35 cl++; 36 while(1) 37 { 38 int z=sta[sl--]; 39 scc[z]=cl; 40 sum[cl]++; 41 if(z==x) break; 42 } 43 } 44 } 45 46 int dfs(int x) 47 { 48 int ans=0; 49 bj[x]=1; 50 for(int i=1;i<=cl;i++) if(map[x][i]==1&&bj[i]==0) 51 ans=mymax(ans,dfs(i)); 52 ans+=sum[x]; 53 bj[x]=0; 54 return ans; 55 } 56 57 int main() 58 { 59 int T; 60 scanf("%d",&T); 61 while(T--) 62 { 63 int n,m,ans=0; 64 scanf("%d%d",&n,&m); 65 memset(first,0,sizeof(first)); 66 memset(dfn,0,sizeof(dfn)); 67 memset(sum,0,sizeof(sum)); 68 memset(bj,0,sizeof(bj)); 69 memset(map,0,sizeof(map)); 70 memset(scc,0,sizeof(scc)); 71 cnt=0;sl=0;cl=0; 72 for(int i=1;i<=m;i++) 73 { 74 int x,y; 75 scanf("%d%d",&t[i].x,&t[i].y); 76 t[i].next=first[t[i].x];first[t[i].x]=i; 77 } 78 for(int i=1;i<=n;i++) if(dfn[i]==0) ffind(i); 79 for(int i=1;i<=m;i++) if(scc[t[i].x]!=scc[t[i].y]) map[scc[t[i].x]][scc[t[i].y]]=1; 80 for(int i=1;i<=cl;i++) ans=mymax(ans,dfs(i)); 81 printf("%d ",ans); 82 } 83 return 0; 84 }
2016-03-17 16:54:20