zoj 2682 People like People

People like People

Time Limit: 2 Seconds      Memory Limit: 65536 KB

The students in Kim��s class did a popularity vote to determine who were popular in the class. Each student was asked to write down the ID numbers of at most three students, except himself/herself, whom he or she liked. After the vote was over and popular students were chosen, Kim, looking at the vote result, was curious to solve the following math question: What was the largest core?

A set of students is called a core if every student in the set

  • voted,
  • liked some students in it but no one outside it, and
  • was liked by some one in it.

More formally, each student will be represented by his or her student ID number from {1, 2, ... , N}, where the class has N students. For example, the table below shows the result of a vote by 12 students in Kim��s class.

Student numberThe numbers written down
14, 8
29, 12, 3
48
51, 6
65
78
81
108, 7, 6
1210

Students 3, 9, and 11 were absent from school and did not vote, so they do not appear in the left column of the table.

Kim found the set {1, 4, 5, 6, 8} to be a core; every student in it voted, liked some students in it but not outside it, and was liked by some one in it. More specifically, 1 liked {4, 8}, 4 liked {8}, 5 liked {1, 6}, 6 liked {5}, and 8 liked {1}. They collectively liked {4, 8, 1, 6, 5}, which are themselves. The number of students in this set is five. {1, 4, 8} is also a core, but it is smaller. As a matter of fact, no core with six or more students is possible from the table. Thus, the size of the largest core of the vote result above is five.

Write a program to find the size of the largest core of a vote result.

Input

The input consists of T test cases. The number of test cases (T) is given on the first line of the input file. The first line of each test case contains two integers N and M, where N (1 <= N <= 10000) is the number of students in the class, and M is the number of students who voted. Each of the following M lines is to begin with an integer i representing a student ID number in {1, 2, ... , N}, which is to be followed by an integer Ni (1 <= Ni <= 3) Ni representing the number of students written down by student i, which is to be followed in turn by a sequence of Ni integers representing the ID numbers written down by student i.

Output

Print exactly one line for each test case. The line is to contain an integer that is the size of the largest core. The following shows sample input and output for two test cases.

Sample Input

1
12 9
1 2 4 8
2 3 9 12 3
4 1 8
5 2 1 6
6 1 5
7 1 8
8 1 1
10 3 8 7 6
12 1 10

Sample Output

5


题目大意:给定一些人的投票,表示他喜欢哪些人。求满足条件的集合中最多有多少人。

                   要求:对于集合里的每个人,1:他必须投过票,2:他喜欢的人必须在集合里,3:集合里有人喜欢他

分析:先拓扑一次,不断把入度为0的点(即没有人喜欢)删掉,在dfs一次,把没有投过票的以及喜欢他们的人删掉,最后求剩下的人中能连通的最大值

#include<cstdio>
#include<stack>
#include<vector>
using namespace std;
const int N=10002;
vector<int> g[N],og[N];
int in_d[N],out_d[N],n;
bool vis[N];
void Top(){
	int i,u,v;
	stack<int> S;
	while(!S.empty())S.pop();
	for(i=1;i<=n;i++){
		if(in_d[i]==0)S.push(i),vis[i]=1;
	}
	while(!S.empty()){
		u=S.top(),S.pop();
		for(i=0;i<g[u].size();i++){
			v=g[u][i];
			in_d[v]--;
			if(in_d[v]==0)S.push(v),vis[v]=1;
		}
	}
}
void dfs(int u){
	vis[u]=1;
	for(int i=0;i<og[u].size();i++)if(!vis[og[u][i]])dfs(og[u][i]);
}
int cal(int u){
	int i,v,res=1;
	vis[u]=1;
	for(i=0;i<g[u].size();i++){
		v=g[u][i];
		if(!vis[v])res+=cal(v);
	}
	for(i=0;i<og[u].size();i++){
		v=og[u][i];
		if(!vis[v])res+=cal(v);
	}
	return res;
}
int main(){
	int T,m,i,j,k;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		for(i=1;i<=n;i++){
			g[i].clear();og[i].clear();
			in_d[i]=out_d[i]=0;
			vis[i]=0;
		}
		while(m--){
			scanf("%d%d",&i,&j);
			while(j--){
				scanf("%d",&k);
				g[i].push_back(k);
				og[k].push_back(i);
				in_d[k]++,out_d[i]++;
			}
		}
		Top();
		for(i=1;i<=n;i++)if(out_d[i]==0)dfs(i);
		int ans=0,tmp;
		for(i=1;i<=n;i++)if(!vis[i]){
			tmp=cal(i);
			if(ans<tmp)ans=tmp;
		}
		printf("%d\n",ans);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值