题意:对于一个有向图,问最大团中有多少点,要求该点集内所有点对间至少有一条路径(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 }
时间: 2024-12-06 17:55:38