标签:
题意:对于一个有向图,问最大团中有多少点,要求该点集内所有点对间至少有一条路径(u到v或v到u或两条都有)。
首先,对于每一个强连通分量,其中的所有点必然能够互相到达,所以先进行缩点,然后对于缩点后的 DAG,dp[i] 表示从 i 强连通分量开始能够到达的最多的点数,那么在缩点时需要记录一下每个强连通分量的点数。然后进行DP,初始值定为该强连通分量的点数,然后用它能到达的点来更新它本身。取最大值就行了。
1 #include<stdio.h>
2 #include<string.h>
3 #include<stack>
4 #include<queue>
5 using namespace std;
6
7 const int maxn=1005;
8 const int maxm=50005;
9
10 int head[2][maxn],point[2][maxm],nxt[2][maxm],size[2];
11 int n,t,scccnt;
12 int stx[maxn],low[maxn],scc[maxn],num[maxn],dp[maxn];
13 stack<int>S;
14
15 void init(){
16 memset(head,-1,sizeof(head));
17 size[0]=size[1]=0;
18 memset(dp,0,sizeof(dp));
19 }
20
21 void add(int a,int b,int c=0){
22 point[c][size[c]]=b;
23 nxt[c][size[c]]=head[c][a];
24 head[c][a]=size[c]++;
25 }
26
27 void dfs(int s){
28 stx[s]=low[s]=++t;
29 S.push(s);
30 for(int i=head[0][s];~i;i=nxt[0][i]){
31 int j=point[0][i];
32 if(!stx[j]){
33 dfs(j);
34 low[s]=min(low[s],low[j]);
35 }
36 else if(!scc[j]){
37 low[s]=min(low[s],stx[j]);
38 }
39 }
40 if(low[s]==stx[s]){
41 scccnt++;
42 while(1){
43 int u=S.top();S.pop();
44 scc[u]=scccnt;
45 num[scccnt]++;
46 if(s==u)break;
47 }
48 }
49 }
50
51 void setscc(){
52 memset(stx,0,sizeof(stx));
53 memset(scc,0,sizeof(scc));
54 memset(num,0,sizeof(num));
55 t=scccnt=0;
56 for(int i=1;i<=n;++i)if(!stx[i])dfs(i);
57 for(int i=1;i<=n;++i){
58 for(int j=head[0][i];~j;j=nxt[0][j]){
59 int k=point[0][j];
60 if(scc[i]!=scc[k]){
61 add(scc[i],scc[k],1);
62 }
63 }
64 }
65 }
66
67 void dfs1(int s){
68 if(dp[s])return;
69 dp[s]=num[s];
70 for(int i=head[1][s];~i;i=nxt[1][i]){
71 int j=point[1][i];
72 dfs(j);
73 if(num[s]+dp[j]>dp[s])dp[s]=num[s]+dp[j];
74 }
75 }
76
77 int main(){
78 int T;
79 scanf("%d",&T);
80 while(T--){
81 int m;
82 scanf("%d%d",&n,&m);
83 init();
84 while(m--){
85 int a,b;
86 scanf("%d%d",&a,&b);
87 add(a,b);
88 }
89 setscc();
90 int ans=0;
91 for(int i=1;i<=scccnt;++i){
92 dfs1(i);
93 if(ans<dp[i])ans=dp[i];
94 }
95 printf("%d\n",ans);
96 }
97 return 0;
98 }
标签:
原文地址:http://www.cnblogs.com/cenariusxz/p/4799160.html