链接:Click
Me!
P1023Victoria的舞会3
描写叙述
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。
题意:
给定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;
}