zjoi 2007 semi 最大半连通子图 强连通分量 动态规划

题意:一个有向图称为半连通的(Semi-Connected),如果满足:

,即对于图中任意两点u,v, 存在一条uv的有向路径或者从vu的有向路径。 

若满足,则称G’是G的一个导出子图。

G’G的导出子图,且G’半连通,则称G’G的半连通子图。

G’G所有半连通子图中包含节点数最多的,则称G’G的最大半连通子图。

给定一个有向图G,请求出G的最大半连通子图拥有的节点数K,以及不同的最大半连通子图的数目C。由于C可能比较大,仅要求输出CX的余数。

思路:强连通分量缩点 DP

  1 #include<iostream>
2 #include<cstdio>
3 #include<cmath>
4 #include<cstring>
5 #include<ctime>
6 using namespace std;
7 #define MAXN 100011
8 #define MAXM 4000011
9 struct node
10 {
11 int num;
12 node *next;
13 };
14 int finish[MAXN],mark[MAXN],dp[MAXN],num[MAXN],sum[MAXN];
15 node *graph[MAXN],*grapht[MAXN],*graphnew[MAXN],*map[MAXN];
16 node memo[MAXM];
17 bool use[MAXN];
18 int top,color,mod,t=0;
19 int n,m;
20 void add(int x,int y,node *graph[])
21 {
22 node *p=&memo[top++];
23 p->num=y; p->next=graph[x]; graph[x]=p;
24 }
25 void dfs(int i)
26 {
27 use[i]=1;
28 for(node *p=graph[i];p;p=p->next)
29 if(!use[p->num]) dfs(p->num);
30 finish[++t]=i;
31 }
32 void dfst(int i)
33 {
34 use[i]=1;
35 mark[i]=color;
36 add(color,i,map);
37 sum[color]++;
38 for(node *p=grapht[i];p;p=p->next)
39 if(!use[p->num]) dfst(p->num);
40 }
41 void connect()
42 {
43 int i;
44 memset(use,0,sizeof(use));
45 for(i=1;i<=n;i++)
46 if(!use[i]) dfs(i);
47 memset(use,0,sizeof(use));
48 for(i=n;i>0;i--)
49 if(!use[finish[i]])
50 {
51 color++;
52 dfst(finish[i]);
53 }
54 }
55 void reduce()
56 {
57 memset(use,0,sizeof(use));
58 int i;
59 int u,v;
60 for(i=1;i<=color;i++)
61 {
62 u=i;
63 for(node *t=map[i];t;t=t->next)
64 for(node *p=graph[t->num];p;p=p->next)
65 {
66 v=mark[p->num];
67 if(u==v) continue;
68 if(!use[v])
69 {
70 use[v]=1;
71 add(u,v,graphnew);
72 }
73 }
74 for(node *t=map[i];t;t=t->next)
75 for(node *p=graph[t->num];p;p=p->next)
76 use[mark[p->num]]=0;
77 }
78 }
79 void dynamic()
80 {
81 int i;
82 for(i=1;i<=color;i++)
83 {
84 dp[i]=sum[i]; num[i]=0;
85 }
86 int ans=0,ans_num=0;
87 for(i=1;i<=color;i++)
88 {
89 if(dp[i]==sum[i]) num[i]=1;
90 if(dp[i]>ans) ans=dp[i];
91 for(node *p=graphnew[i];p;p=p->next)
92 {
93 if(dp[i]+sum[p->num]>dp[p->num])
94 dp[p->num]=dp[i]+sum[p->num];
95 }
96 }
97 printf("%d\n",ans);
98 for(i=1;i<=color;i++)
99 {
100 for(node *p=graphnew[i];p;p=p->next)
101 {
102 if(dp[i]+sum[p->num]==dp[p->num])
103 num[p->num]=(num[i]+num[p->num])%mod;
104 }
105 if(ans==dp[i]) ans_num=(num[i]+ans_num)%mod;
106 }
107 printf("%d\n",ans_num);
108 }
109
110 int main()
111 {
112 freopen("semi.in","r",stdin);
113 freopen("semi.out","w",stdout);
114 top=color=0;
115 memset(map,0,sizeof(map));
116 memset(sum,0,sizeof(sum));
117 memset(graph,0,sizeof(graph));
118 memset(grapht,0,sizeof(grapht));
119 memset(graphnew,0,sizeof(graphnew));
120 scanf("%d%d%d",&n,&m,&mod);
121 node *p;
122 int i;
123 int x,y;
124 for(i=1;i<=m;i++)
125 {
126 scanf("%d%d",&x,&y);
127 add(x,y,graph); add(y,x,grapht);
128 }
129 connect();
130 reduce();
131 dynamic();
132 return 0;
133 }



原文地址:https://www.cnblogs.com/myoi/p/2418685.html