【洛谷3852】小朋友(弦图)
【洛谷3852】小朋友(弦图)
题面
题目背景
幼儿园里有N个小朋友,老师要从中选出来一部分做丢手绢的游戏,可是老师没有想到这么小的孩子里面有些人之间还有矛盾。老师想找出尽量多的小朋友去玩游戏,但是又很头疼,他不想看到找出来玩游戏的小朋友里面还有任何两个人之间存在着矛盾。如果告诉你小朋友之间存在的M对矛盾关系,你能否帮助幼儿园老师计算出他最多可以选出多少个小朋友来做这个丢手绢的游戏?
题目描述
关于矛盾限制的说明:
如果我们把存在着矛盾的两个小朋友看作是无向图中相连的两个点,那么题目中的数据保证M对矛盾所构成的图中不会有超过3个点的环。(图1符合要求,图2则不符合)
输入输出格式
输入格式:
输入文件的第一行是用空格隔开的两个整数N和M,表示一共有N个小朋友,这些小朋友之间有M对矛盾关系。接下来的M行,每行将有一对整数a和b(用空格隔开),表示小朋友a与小朋友b有矛盾。(小朋友的编号都是从1开始的)
输出格式:
输出一行,包含一个整数,即幼儿园老师最多可以选出来做游戏的人数。
题解
给出来的环不超过\(3\)???
很明显是一个弦图
现在要求的就是弦图的最大独立集
用最大势算法求出完美消除序列之后
按照序列贪心,能选则选
最后选出来的就是答案
有关于弦图的内容
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 222
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
struct Line{int v,next;}e[MAX*MAX];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
vector<int> V[MAX];
int n,m,label[MAX],seq[MAX],tot;
bool vis[MAX];
int main()
{
n=read();m=read();
for(int i=1;i<=m;++i)
{
int u=read(),v=read();
Add(u,v);Add(v,u);
}
for(int i=1;i<=n;++i)V[0].push_back(i);
for(int t=1,now,best=0;t<=n;++t)
{
bool fl=false;
while(!fl)
{
for(int i=V[best].size()-1;~i;--i)
if(!vis[V[best][i]]){now=V[best][i];fl=true;break;}
else V[best].pop_back();
if(!fl)--best;
}
seq[t]=now;vis[now]=true;
for(int i=h[now];i;i=e[i].next)
if(!vis[e[i].v])
{
V[++label[e[i].v]].push_back(e[i].v);
best=max(best,label[e[i].v]);
}
}
memset(vis,0,sizeof(vis));
int ans=0;
for(int i=n;i;--i)
if(!vis[seq[i]])
{
++ans;vis[seq[i]]=true;
for(int j=h[seq[i]];j;j=e[j].next)
vis[e[j].v]=true;
}
printf("%d\n",ans);
return 0;
}