People like People ZJU 2682 强联通+记忆化搜索

题意:

 给定一个有向图.

 求一个最大的集合,是所有属于这个集合的点都满足以下条件:

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;
}

你可能感兴趣的:(File,Graph)