首页 > 代码库 > BZOJ1093 [ZJOI2007]最大半连通子图

BZOJ1093 [ZJOI2007]最大半连通子图

首先,我们要tarjan。。。 然后我们要缩点。。。

注意,缩点的时候两个新建的点会有重边,需要判重

正常的判重方法是bfs一边,但是我YY的比较奇葩,方法下面将。。。

缩好点就变成了一个DAG,然后就类似树形DP的方法求最大权值链

我是用记忆化搜索,当dfs某个点p时用数组vis记录一些东西:

首先vis[x] > 0代表x已经访问过了, vis[x] == p表示vis[x]上次是由p来的,于是就可以去重了。。。

然后就没有然后了,搞定yeah!

 

 1 /************************************************************** 2     Problem: 1093 3     User: rausen 4     Language: C++ 5     Result: Accepted 6     Time:1604 ms 7     Memory:31220 kb 8 ****************************************************************/ 9  10 #include <cstdio>11 #include <algorithm>12 #include <cstring>13  14 using namespace std;15 const int inf = (int) 1e8;16 struct edges{17     int from, to, next;18 }e[2000005];19  20 int first[100005],tot;21 int dfn[100005], low[100005], w[100005], sum[100005];22 int vis[100005], s[100005], f[100005], g[100005], F[100005];23 int n, m, MOD, X, Y, ans, top, cnt, num, ANS;24  25 void add_edge(int x, int y){26     e[++tot].next = first[x];27     first[x] = tot;28     e[tot].from = x, e[tot].to = y;29 }30  31 void tarjan(int p){32     dfn[p] = low[p] = ++cnt;33     s[++top] = p;34     vis[p] = 1;35     int x, y;36     for (x = first[p]; x; x = e[x].next){37         y = e[x].to;38         if (!vis[y]) tarjan(y);39         if (vis[y] < 2)40             low[p] = min(low[p], low[y]);41     }42     if (dfn[p] == low[p]){43         ++num;44         while (s[top + 1] != p){45             int y = s[top--];46             vis[y] = 2, w[y] = num;47             ++sum[num];48         }49     }50 }51  52 void dfs(int p){53     if (vis[p]) return;54     vis[p] = inf;55     int x, y;56     for (int x = first[p]; x; x = e[x].next){57         y = e[x].to;58         if (vis[y] == p) continue;59         vis[y] = p;60         dfs(y);61         if (f[p] < f[y])62             f[p] = f[y], g[p] = g[y]; else63         if (f[p] == f[y]) g[p] += g[y];64     }65     g[p] %= MOD;66     f[p] += sum[p];67     if (ans < f[p])68         ans = f[p], ANS = g[p]; else69     if (ans == f[p]) ANS += g[p], ANS %= MOD;70 }71  72 int main(){73     scanf("%d%d%d", &n, &m, &MOD);74     for (int i = 1; i <= m; ++i)75         scanf("%d%d", &X, &Y), add_edge(X, Y);76     for (int i = 1; i <= n; ++i)77         if (!vis[i]) tarjan(i);78      79     memset(first, 0, sizeof(first));80     tot = 0;81     for (int i = 1; i <= m; ++i){82         X = e[i].from;83         Y = e[i].to;84         if (w[X] != w[Y]) add_edge(w[X], w[Y]);85     }86     memset(vis, 0, sizeof(vis));87     for (int i = 1; i <= num; ++i)88         if (!first[i]) g[i] = 1;89     for (int i = 1; i <= num; ++i)90         if (!vis[i]) dfs(i);91     printf("%d\n%d\n", ans, ANS % MOD);92     return 0;93 }
View Code

(p.s. 各种压代码+卡内存此题status终于上了前两页。。。)

BZOJ1093 [ZJOI2007]最大半连通子图