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;
}
posted @ 2022-08-07 09:55  Code_AC  阅读(46)  评论(0编辑  收藏  举报