Vijos P1023Victoria的舞会3【贪心+DFS求强联通分量】

链接:Click Me!

P1023Victoria的舞会3
Accepted
标签: Victoria的舞会 [显示标签]

描述

Victoria是一位颇有成就的艺术家,他因油画作品《我爱北京天安门》闻名于世界。现在,他为了报答帮助他的同行们,准备开一个舞会。

Victoria准备邀请n个已经确定的人,可是问题来了:
这n个人每一个人都有一个小花名册,名册里面写着他能够通知到的人的名字。比如说在A的人名单里写了B,那么表示A能够通知到B;但是B的名单里不见的有A,也就是说B不见得通知到A。

Victoria觉得需要确定自己需要通知多少个人m,能够实际将所有人n都通知到。并求出一种方案以确定m的最小值是多少。

注意:自己的名单里面不会有自己的名字。Victoria可以自身通知到所有n个人。

格式

输入格式

第一行一个数n。接下来n行,每i+1行表示编号为i的人的小花名册名单,名单以0结束。\

1<=n<=200。

输出格式

一个数,m。

样例1

样例输入1[复制]

18
0
11 0
0
0
0
16 0
14 0
0
0
0
2 13 0
0
11 0
7 0
0
6 0
0
0

样例输出1[复制]

14

题意:

给定N个顶点,每个顶点将于其他若干个点单向连通,求最少用几个顶点可以把这N个顶点构成一个单向连通图。

分析:

遍历每个顶点,如果这个顶点之前没有被标记,并且,它连接的节点全未被标记,那么可以将答案加1,然后将它可以到达的顶点DFS标记;如果这个顶点之前没有被标记,并且,它连接的节点有一个被标记,那么因为它连接的节点既然被标记了,那么,先标记该节点,那么与它相连的其他节点自然会被标记,而且,得到的ans 不会比之前的大,【贪心策略】,,如果遍历的当前节点之前就被标记了,那么这个节点就直接跳过,此时考虑这个节点是没有意义的了。

代码实现:

#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
#define CASE(T)         for(scanf("%d",&T);T--;)
typedef long long LL;
const int maxn = 200 + 5;
const int INF = 0x3f3f3f3f;
int N, M, ans;
vector<int> G[maxn];
bool vis[maxn];
void init()
{
    memset(vis, false, sizeof(vis));
    for(int i = 1; i <= N; i++)
    {
        G[i].clear();
    }
}
void Mark(int cur)
{
    if(vis[cur]) return;
    vis[cur] = true;
    for(int i = 0; i < G[cur].size(); i++)
    {
        if(vis[G[cur][i]]) continue;
        Mark(G[cur][i]);
    }
}
inline bool judge(int x)
{
    for(int i = 0; i < G[x].size(); i++)
        if(vis[G[x][i]]) return false;
    return true;
}
int main()
{
    // FIN;
    int t;
    while(~scanf("%d", &N))
    {
        init();
        for(int i = 1; i <= N; i++)
        {
            while(1)
            {
                scanf("%d", &t);
                if(t == 0) break;
                G[i].push_back(t);
            }
        }
        ans = 0;
        for(int i = 1; i <= N; i++)
        {
            if(vis[i]) continue;
            if(judge(i)) ans++;
            Mark(i);
        }
        printf("%d\n", ans);
    }
    return 0;
}



你可能感兴趣的:(强连通分量)