题目描述
开会,是对所有人时间的浪费,是对集体的谋杀。
山区学校的一些学生之间的关系似乎好得有点过头,以至于传出了一些(在风纪委员们看来)不好的绯闻。具体地,有n个学生,n-1条绯闻,每条绯闻的主角都是俩学生。记者们的恶趣味保证任意两个学生,可以通过若干条绯闻直接或间接地联系在一起。
于是学校打算邀请一些学生参加座谈会。
校长相信,假如邀请了某位学生x来开会,那么就能够震慑到x本人,以及和x在同一条绯闻里的学生们。
矿泉水是宝贵的,校长想知道最少需要请多少人来开会,才有可能震慑到所有同学。
输入
第一行是 n 表示学生数。
之后n-1行,每行俩整数x,y,表示学生x和y之间有绯闻。( x≠y,但不一定x<y )
输出
一行,一个整数表示最少要邀请多少人。
样例输入
5 1 3 5 2 4 3 3 5
样例输出
2
提示
可以选择邀请学生2&3,或者是邀请学生3&5
对于前10%的数据,n<=15
对于前30%的数据,n<=2000
对于接下来30%的数据,n<=10^5,且有俩学生需要通过n-1条绯闻才能扯上关系。
对于前100%的数据,n<=10^5,1<=x,y<=n
【题解】:
最小支配集:模板题
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+1000;
typedef struct Edge{
int v,next;
Edge(int v=0,int next=0):v(v),next(next){}
}Edge;
Edge e[N*2];
int head[N],cnt,n;
int vis[N];
void add_edge(int u,int v){
e[cnt]=Edge(v,head[u]);
head[u]=cnt++;
}
int pre[N];
void dfs(int u,int father){
pre[u]=father;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].v;
if(v==father) continue;
dfs(v,u);
}
}
stack < int > St;
queue < int > q;
void bfs(){
q.push(1);
St.push(1);
while(!q.empty()){
int cur = q.front();
q.pop();
for(int i=head[cur];~i;i=e[i].next){
int v=e[i].v;
if(v==pre[cur])continue;
q.push(v);
St.push(v);
}
}
}
void solve(){
int ans=0;
while(!St.empty()){
int cur=St.top();
St.pop();
if(vis[cur]==0){
vis[pre[cur]]=1;
for(int i=head[pre[cur]];~i;i=e[i].next){
int v=e[i].v;
vis[v]=1;
}
ans++;
}
}
printf("%d\n",ans);
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d",&n);
int u,v;
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
dfs(1,0);
bfs();
solve();
return 0;
}