<题目链接>

题目大意:

给你一张有向图 G,求一个结点数最大的结点集,使得该结点集中的任意两个结点 u 和 v 满足:要么 u 可以达 v,要么 v 可以达 u(u,v相互可达也行)。

解题分析:

该点集需满足两个要求:1.任意两点至少有一方能够到达另外一点;2.点数尽可能的多。

通过画图分析可以知道,对于那些强连通分量来说,要不就全部加入该点集,要不就全部不能加入,所以直接对原图进行缩点,进行重新构图。然后,根据重新构造的DAG图我们可以知道,要使该点集中任意两点至少有一方能够到达另外一点,并且要求点数尽可能的多,可以发现,其实就是让我们求缩点后的最长路。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <vector>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 #define pb push_back
 8 #define clr(a,b) memset(a,b,sizeof(a))
 9 #define rep(i,s,t) for(int i=s;i<=t;i++)
10 const int N = 1e3+10,M = 5e4+10;
11 int n,m,tot,tott,top,scc;
12 int head[N],belong[N],dfn[N],low[N],stk[N],instk[N],dp[N],cnt[N];
13 vector<int>G[N];
14 struct Edge{
15     int to,next;
16 }edge[M];
17 void init(){
18     rep(i,0,n)G[i].clear();
19     tot=scc=top=tott=0;
20     clr(head,-1);clr(low,0);clr(dfn,0);clr(stk,0);clr(instk,0);clr(belong,0);clr(dp,0);clr(cnt,0);
21 }
22 void addedge(int u,int v){
23     edge[++tot].to=v,edge[tot].next=head[u];
24     head[u]=tot;
25 }
26 void Tarjan(int u){       //进行缩点
27     dfn[u]=low[u]=++tott;
28     stk[++top]=u;instk[u]=1;
29     for(int i=head[u];~i;i=edge[i].next){
30         int v=edge[i].to;
31         if(!dfn[v]){
32             Tarjan(v);
33             low[u]=min(low[u],low[v]);
34         }else if(instk[v])low[u]=min(low[u],dfn[v]);
35     }
36     if(dfn[u]==low[u]){
37         scc++;
38         while(true){
39             int v=stk[top--];
40             instk[v]=0;
41             belong[v]=scc;
42             cnt[scc]++;
43             if(v==u)break;
44         }
45     }
46 }
47 //记忆化搜索求以u为起点的最长路,点权为"点"中点的个数
48 int DFS(int u){
49     if(dp[u])return dp[u];
50     int ans=cnt[u];
51     for(int i=0;i<G[u].size();i++){
52         int v=G[u][i];
53         ans=max(ans,DFS(v)+cnt[u]);
54     }
55     return dp[u]=ans;
56 }
57 int main(){
58     int T;scanf("%d",&T);while(T--){
59         init(); 
60         scanf("%d%d",&n,&m);
61         rep(i,1,m){
62             int u,v;scanf("%d%d",&u,&v);
63             addedge(u,v);
64         }
65         rep(i,1,n)
66             if(!dfn[i])Tarjan(i);
67         //对图进行缩点,重新构图
68         rep(u,1,n) for(int i=head[u];~i;i=edge[i].next){
69             int v=edge[i].to;
70             if(belong[u]!=belong[v])
71                 G[belong[u]].pb(belong[v]);
72         }
73         int ans=0;
74         rep(i,1,scc)
75             ans=max(ans,DFS(i));   //求缩点后图的最长路
76         printf("%d\n",ans);
77     }
78 }

 

 

2018-11-28