ZOJ3795 Grouping(强连通分量+缩点+记忆化搜索)

题目给一张有向图,要把点分组,问最少要几个组使得同组内的任意两点不连通。

首先考虑找出强连通分量缩点后形成DAG,强连通分量内的点肯定各自一组,两个强连通分量的拓扑序能确定的也得各自一组。

能在同一组的就是两个强连通分量在不同的从入度0到出度0的强连通分量的路径上。

那么算法很直观就能想到了,用记忆化搜索,d[u]表示从强连通分量u出发到出度为0的强连通分量最少要几个组(最多有几个点)。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define MAXN 110000
 6 #define MAXM 330000
 7 struct Edge{
 8     int u,v,next;
 9 }edge[MAXM];
10 int head[MAXN],NE;
11 void addEdge(int u,int v){
12     edge[NE].u=u; edge[NE].v=v; edge[NE].next=head[u];
13     head[u]=NE++;
14 }
15 int bn,belong[MAXN],size[MAXN];
16 int dn,dfn[MAXN],low[MAXN];
17 int top,stack[MAXN]; bool instack[MAXN];
18 void tarjan(int u){
19     dfn[u]=low[u]=++dn;
20     stack[++top]=u; instack[u]=1;
21     for(int i=head[u]; i!=-1; i=edge[i].next){
22         int v=edge[i].v;
23         if(dfn[v]==0){
24             tarjan(v);
25             low[u]=min(low[u],low[v]);
26         }else if(instack[v]){
27             low[u]=min(low[u],dfn[v]);
28         }
29     }
30     if(dfn[u]==low[u]){
31         int v; ++bn;
32         do{
33             v=stack[top--];
34             instack[v]=0;
35             belong[v]=bn; ++size[bn];
36         }while(u!=v);
37     }
38 }
39 int d[MAXN];
40 int dfs(int u){
41     if(d[u]) return d[u];
42     int res=0;
43     for(int i=head[u]; i!=-1; i=edge[i].next){
44         int v=edge[i].v;
45         res=max(res,dfs(v));
46     }
47     return d[u]=res+size[u];
48 }
49 int main(){
50     int n,m,a,b;
51     while(~scanf("%d%d",&n,&m)){
52         NE=0;
53         memset(head,-1,sizeof(head));
54         while(m--){
55             scanf("%d%d",&a,&b);
56             addEdge(a,b);
57         }
58         top=dn=bn=0;
59         memset(dfn,0,sizeof(dfn));
60         memset(instack,0,sizeof(instack));
61         memset(size,0,sizeof(size));
62         for(int i=1; i<=n; ++i){
63             if(dfn[i]==0) tarjan(i);
64         }
65         
66         int tmp=NE; NE=0;
67         memset(head,-1,sizeof(head));
68         for(int i=0; i<tmp; ++i){
69             int u=belong[edge[i].u],v=belong[edge[i].v];
70             if(u==v) continue;
71             addEdge(u,v);
72         }
73         memset(d,0,sizeof(d));
74         int res=0;
75         for(int i=1; i<=bn; ++i){
76             res=max(res,dfs(i));
77         }
78         printf("%d\n",res);
79     }
80     return 0;
81 }

 

你可能感兴趣的:(ZOJ3795 Grouping(强连通分量+缩点+记忆化搜索))