求图的最大半连通子图(什么是半连通参考POJ 2762)。
由于在对原图缩点以后,半连通就变成DAG上的一条链。那么答案就是DAG上的最长链。一个DP即可。
注意要处理重边。。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
#define FOR(i,j,k) for(i=j;i<=k;++i)
#define ms(a, b) memset(a, b, sizeof a)
const int N = 100004, M = 1000004;
int top, ts, in[N], belong[N], num[N], sol[N], dis[N], instack[N], stack[N], low[N], dfn[N], scc;
set<pair<int, int> > mp;
struct Graph {
int h[N], p[M], v[M], cnt;
Graph() { ms(h, 0); cnt = 0; }
void add(int a, int b) {
p[++cnt] = h[a]; v[cnt] = b; h[a] = cnt;
}
} g, c;
void tarjan(int x) {
int i;
dfn[x] = low[x] = ++ts;
stack[++top] = x; instack[x] = 1;
for (i = g.h[x]; i; i = g.p[i])
if (!dfn[g.v[i]]) {
tarjan(g.v[i]);
low[x] = min(low[x], low[g.v[i]]);
} else if (instack[g.v[i]])
low[x] = min(low[x], dfn[g.v[i]]);
if (dfn[x] == low[x]) {
++scc;
do {
i = stack[top--];
instack[i] = 0;
belong[i] = scc;
++num[scc];
} while (i != x);
}
}
void bfs(int x) {
static int q[N];
int i, f = 0, r = 0;
FOR(i,1,scc) dis[i] = 0, sol[i] = 0;
FOR(i,1,scc) if (!in[i]) q[r++] = i, dis[i] = 0, sol[i] = 1;
while (f < r) {
int u = q[f++];
dis[u] += num[u];
for (i = c.h[u]; i; i = c.p[i]) {
if (dis[c.v[i]] < dis[u]) {
dis[c.v[i]] = dis[u];
sol[c.v[i]] = sol[u];
} else if (dis[c.v[i]] == dis[u])
(sol[c.v[i]] += sol[u]) %= x;
if (--in[c.v[i]] <= 0) q[r++] = c.v[i];
}
}
}
int main() {
int a, b, i, j, n, m, x, k = 0, l = 0;
scanf("%d%d%d", &n, &m, &x);
ts = top = scc = 0;
FOR(i,1,m) scanf("%d%d", &a, &b), g.add(a, b);
FOR(i,1,n) if (!dfn[i]) tarjan(i);
FOR(i,1,n) for (j = g.h[i]; j; j = g.p[j])
if (belong[i] != belong[g.v[j]] && !mp.count(make_pair(belong[i], belong[g.v[j]]))) {
mp.insert(make_pair(belong[i], belong[g.v[j]]));
++in[belong[g.v[j]]]; c.add(belong[i], belong[g.v[j]]);
}
bfs(x);
FOR(i,1,scc) if (!c.h[i]) k = max(k, dis[i]);
FOR(i,1,scc) if (dis[i] == k) (l += sol[i]) %= x;
printf("%d\n%d\n", k, l);
return 0;
}
1093: [ZJOI2007]最大半连通子图
Time Limit: 30 Sec Memory Limit: 162 MB
Submit: 2449 Solved: 972
Description
Input
第一行包含两个整数N,M,X。N,M分别表示图G的点数与边数,X的意义如上文所述。接下来M行,每行两个正整数a, b,表示一条有向边(a, b)。图中的每个点将编号为1,2,3…N,保证输入中同一个(a,b)不会出现两次。
Output
应包含两行,第一行包含一个整数K。第二行包含整数C Mod X.
Sample Input
6 6 20070603
1 2
2 1
1 3
2 4
5 6
6 4
Sample Output
3
3
HINT
对于100%的数据, N ≤100000, M ≤1000000;对于100%的数据, X ≤10^8。