题意:
给定一个有向图.
求一个最大的集合,是所有属于这个集合的点都满足以下条件:
1.出度不为0
2.指向的点都在这个集合内
3.有属于这个集合的点指向这个点
题解:
我的做法是:对图缩点后,枚举每个点,以这个点作起点,并且这个点是由大于等于2个点缩点而得到的,然后这个点为根,以他能访问到的点构成树,如果所有叶子都是大于等于两个点以上缩点得到的,则说明该树构成一个合法的集合.取最大的合法集合即可.
/*
* File: main.cpp
* Author: swordholy
*
* Created on 2011年3月6日, 下午1:27
*/
#include <cstdlib>
#include <iostream>
#include <memory.h>
#include <stdio.h>
#include<iostream>
#include<vector>
using namespace std;
#define MY_MAX 100004
bool visited[MY_MAX], instack[MY_MAX];
int stack[MY_MAX], top;
int N, M;
vector<int> graph[MY_MAX];
vector<int> g[MY_MAX]; //rebuilded
int dfn[MY_MAX], low[MY_MAX];
int color[MY_MAX], colorn[MY_MAX];
int INDEX, num, en;
struct edge {
int x, y;
};
edge e[MY_MAX];
int min(int x, int y) {
if (x < y) return x;
else return y;
}
void tarjan(int u) {
int v;
dfn[u] = low[u] = INDEX++;
stack[++top] = u;
instack[u] = true;
visited[u] = true;
for (size_t i = 0; i < graph[u].size(); ++i) {
v = graph[u][i];
if (!visited[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (instack[v])
low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
++num;
color[u] = num;
do {
v = stack[top--];
color[v] = num;
instack[v] = false;
} while (v != u);
}
}
int d[100005];
int dfs(int x) {
int i, j, sum;
if (d[x] != -1) return d[x];
d[x] = 0;
if ((g[x].size() == 0)) {
if (colorn[x] >= 2) {d[x]=colorn[x];return colorn[x];}
else return 0;
}
sum = colorn[x];
for (i = 0; i < g[x].size(); i++) {
int temp = dfs(g[x][i]);
if (temp == 0) return 0;
sum += temp;
}
d[x] = sum;
return sum;
}
/*
*/
int main(int argc, char** argv) {
int n, i, j, t, u, m, vv, id, idn, v[5];
cin >> t;
for (u = 1; u <= t; u++) {
scanf("%d %d", &n, &m);
for (i = 1; i <= n; i++)
graph[i].clear();
en = 0;
for (vv = 1; vv <= m; vv++) {
scanf("%d %d", &id, &idn);
for (i = 1; i <= idn; i++) {
scanf("%d", &v[i]);
graph[id].push_back(v[i]);
++en;
e[en].x = id;
e[en].y = v[i];
}
}
/* for(i=1;i<=5;i++)
{
for(j=0;j<graph[i].size();j++)
printf("%d ",graph[i][j]);
printf("/n");
}*/
///////////////////////////////////
//init....
top = 0;
num = 0;
INDEX = 1;
memset(visited, 0, sizeof (visited));
memset(instack, 0, sizeof (instack));
//////////////////////////////////
//calc color by tarjan
for (i = 1; i <= n; i++)
if (!visited[i]) tarjan(i);
//////////////////////////////////
//rebuild a map
for (i = 1; i <= n; i++)
g[i].clear();
for (i = 1; i <= en; i++)
if (color[e[i].x] != color[e[i].y])
//不能自己指向自己
g[color[e[i].x]].push_back(color[e[i].y]);
///////////////////////////////////
memset(colorn, 0, sizeof (colorn));
for (i = 1; i <= n; i++)
colorn[color[i]]++;
bool fl = true;
memset(d, -1, sizeof (d));
int ans = 0;
for (i = 1; i <= num; i++)
if (colorn[i] >= 2) {
int v = dfs(i);
if (v > ans) ans = v;
}
printf("%d/n", ans);
}
return 0;
}