2 聚会(party.c/cpp/pas)
2.1 题目描述
你要精心策划一场聚会。
现在有 n 个人,一共有 m 个认识关系,认识的人一定是相互认识的。由于这次聚会十
分重要,你希望被邀请的每个人都直接或间接认识,不仅如此,为了避免尴尬,你还希望每
个被邀请的人都直接认识另外至少 d 个被邀请的人。作为策划者,你希望使得被邀请的人
最多。注意同一对关系最多只会出现一次,且不会出现自环。
你需要输出被邀请的人数,并且将被邀请的人的编号从小到大输出。为了避免你的重度
选择恐惧症发作,当存在多个答案时,你需要使得被邀请的人的编号越小越好。
2.2 输入格式
第一行为三个整数 n,m,d,分别表示人数、认识关系数以及题中给出的限制 d。
接下来 m 行 ,每行两个数 a 和 b,表示 a、b 相互认识。
2.3 输出格式
第一行一个整数,表示被邀请的人数 k。保证有解,即 k>0。
第二行 k 个整数,从小到大输出你邀请的人的编号。
2.4 样例输入
4 4 2
1 2
2 3
3 4
4 2
2.5 样例输出
NOIP 模拟试题 #5
5
3
2 3 4
2.6 数据范围与约定
对于 20%的数据,n<=18,m<=50
对于 100%的数据,2<=n<=200000, 1<=m<=200000 , 1<=d<n
先找出邻接点
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=210000;
int head[maxn],net[2*maxn],to[2*maxn],cnt;
int dfn[maxn],low[maxn],c[maxn],s[maxn],col,num,top;
int sum[maxn];
int no_r[maxn];
bool flag[maxn],f[maxn];
int ans=0,ans_c=0,d_min=1e9;
void add(int a,int b)
{
cnt++;
to[cnt]=b;
net[cnt]=head[a];
head[a]=cnt;
}
void dfs(int x)
{
dfn[x]=++num;
low[x]=num;
f[x]=1;
s[++top]=x;
for(int i=head[x];i;i=net[i])
{
int tmp=to[i];
if(flag[tmp]) continue;
if(dfn[tmp]==0)
{
dfs(tmp);
low[x]=min(low[x],low[tmp]);
}
else
if(f[tmp]==1)
{
low[x]=min(low[x],dfn[tmp]);
}
}
if(low[x]==dfn[x])
{
f[x]=0;
c[x]=++col;
int min1=x;
int tot=1;
while(s[top]!=x)
{
tot++;
min1=min(min1,s[top]);
c[s[top]]=col;
f[s[top--]]=0;
}
top--;
if(tot>ans) ans=tot,ans_c=col;
if(tot==ans)
if(min1<d_min) d_min=min1,ans_c=col;
}
}
int main()
{
int n,m,d;
scanf("%d%d%d",&n,&m,&d);
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
sum[x]++,sum[y]++;
add(x,y),add(y,x);
}
int l=0,r=0;
for(int i=1;i<=n;i++)
if(sum[i]<d) no_r[++r]=i,flag[i]=1;
while(l<=r)
{
l++;
int tmp=no_r[l];
for(int i=head[tmp];i;i=net[i])
if(!flag[to[i]])
{
sum[to[i]]--;
if(sum[to[i]]<d) no_r[++r]=to[i],flag[to[i]]=1;
}
}
for(int i=1;i<=n;i++)
if(!flag[i]&&!dfn[i])
dfs(i);
printf("%d\n",ans);
for(int i=1;i<=n;i++)
if(c[i]==ans_c) printf("%d ",i);
return 0;
}


2193

被折叠的 条评论
为什么被折叠?



