2021年初寒假训练第24场 B. 庆功会(搜索)

Description

NOIP结束之后,为了庆祝同学们取得的优异成绩,学校决定召开一次 Party。发邀请函的工作交到了你的手上。
为了能让这次Party开得圆满顺利,对于这次邀请的同学们有两个要求:首先,每个同学认识的同学不少于a个,否则的话这个同学会感到孤单;其次,每个同学不认识的同学不少于b个,否则的话他(她)就没有机会认识新朋友。
但是学校想让这次Party开得越大越好。所以请你计算一下,最多可以邀请多少个同学?

Input

第一行四个数,N,M,a,b。总共有 N 个同学,这些同学从 1 到 N编号。
后接 MM行,每行两个数 ai、bi,表示这两个同学互相认识。

Output

一行一个数,表示最多可以邀请的同学数。

Samples

Input

4 3 1 1
1 2
2 3
3 4

Output

4

Input

5 5 2 1 
2 3 
3 1 
4 5 
3 4 
2 5

Output

4

Hint

【数据规模】
对于20%的数据,N<20。
对于全部的数据,1≤a,b≤N≤500,0≤M≤N∗(N–1)/2。

思路:

正着考虑不好处理,考虑反着考虑。

假设开始的时候所有人都被选上,那么有哪些人是不应当选的呢。

就是认识的人小于a或是不认识的人小于b的人。

把这些人去除后,会对剩下的人产生影响。

dfs处理就好了。

OJ有点卡快读。

代码:

const int maxn=510;
int mp[maxn][maxn];
int da[maxn],db[maxn];
int n,m,a,b;
bool vis[maxn];
void dfs(int u){
	for(int i=1;i<=n;i++)
		if(!vis[i]){//优化
			if(mp[u][i]) da[i]--;///认识的话,认识的人-1 
			else db[i]--;//否则,不认识的人-1 
			if(da[i]<a||db[i]<b){
				vis[i]=1;
				dfs(i);
			}
		}
} 
void solve(){
	scanf("%d%d%d%d",&n,&m,&a,&b);
//	n=read(),m=read(),a=read(),b=read();
	for(int i=1;i<=m;i++){
		//int u=read(),v=read();
		int u,v;
		scanf("%d%d",&u,&v);
		da[u]++;da[v]++;
		mp[u][v]=mp[v][u]=1;///两人认识 
	}
	for(int i=1;i<=n;i++)
		db[i]=n-da[i]-1;
	for(int i=1;i<=n;i++){
		if(!vis[i]&&(da[i]<a||db[i]<b)){
			///一定不行
			vis[i]=1;
			dfs(i);///该人不来参加对其他人的影响 
		}
	}
	int res=0;
	for(int i=1;i<=n;i++)
		if(!vis[i]) res++;///合理 
	printf("%d\n",res);
}
posted @ 2021-02-03 14:58  OvO1  阅读(41)  评论(0编辑  收藏  举报