P3524题解
题意翻译已在题中很清晰的给出,这里不再多赘述...
题目分析:
首先解释一下团的概念:
团指的是一个图中的完全子图。
这里提供两种思路:
1. 建补图:
补图是什么?
简单理解,就是将原图中未连边的点全部连上,然后把连了的边全部删掉。
打个比方:
看下面这张图:
这就是它的补图:
那么,我们可以想到,先建原图的补图,那么度数大于 \(\dfrac{1}{3}n\) 点在原图中一定无法构成团,那么就把它们都删掉,然后在剩下的点中选即可。
这个做法可行,就不给代码了,可以自己尝试写一下。
2. 观察题目给出的条件:
我们来思考一下 \(n, \dfrac{2}{3}n, \dfrac{1}{3}n\) 这三个两之间的关系:
很明显:
\[n=\dfrac{2}{3}n + \dfrac{1}{3}n
\]
故我们可以想到这样的处理方式:
step1 建图过程中,将有连边的两个点打上标记;
step2 然后找到任意一对没有连边的点,将它们删掉;
step3 由于数据保证有由 \(\dfrac{2}{3}n\) 个点组成的团,所以当我们删掉了 \(\dfrac{1}{3}n\) 对点时,其中的 \(\dfrac{1}{3}n\) 为保证的团中的点,另外 \(\dfrac{1}{3}n\) 则是不包含在团中的点,那么整个图中剩下的 \(\dfrac{1}{3}n\) 个点就必然构成一个 \(\dfrac{1}{3}n\) 个点的团。
这种做法正确性显然。
这种方法给出核心代码:
Code
int n,m,cnt;
bool edge[MAXN][MAXN],vis[MAXN];//edge用来记录是否连边,vis用来删边
int main()
{
n=read(),m=read();
for(register int i=1;i<=m;i++)
{
int x=read(),y=read();
edge[x][y]=edge[y][x]=true;//连边
}
for(register int i=1;i<=n;i++)
for(register int j=1;j<=n;j++)
if(!vis[i]&&!vis[j]&&i!=j&&!edge[i][j])
vis[i]=vis[j]=true;//删边
for(register int i=1;i<=n;i++)
{
if(vis[i])
continue;
if(++cnt==n/3)
{
printf("%d",i);
break;
}
else
printf("%d ",i);
}
return 0;
}