题目超长,可以进链接看原题。


题目概要

题目描述:
在二维空间上有若干个点,有两队(蓝方和绿方),每队都可以占边。
而当有其中一队占的边有可能有三条首尾相连就输出"yes",否则输出"no"。

输入描述:
第一行一个正整数 T,表示数据组数。
每组数据的第一行有两个正整数 n 和 m,表示场上总据点数为 n,此时蓝方已经形成了 m 条控制链。
接下来 m 行,每行有两个正整数 x 和 y,表示这条控制链由据点 x 和据点 y 形成。
(1 ≤ ≤ 10≤ ≤ × 104≤ ≤ 105

输出描述:
对于每组数据,如果目前场上有可能存在被玩家控制的区域,则输出一行 "yes",否则输出一行 "no"。(均不包含引号)


解析

这道题其实可以暴力(但不是全暴),看了大佬的方法懂了。
那我们就来梳理一下思路:
  1. 首先用一个二维数组(edge数组)保存两个点之间的关系(edge[x][y]为0表示中间没边,为1表示中间有边)。
  2. 三条边首尾相连,我们可以简单的枚举出三个点,看是否首尾相连。如果首尾相连直接出来进行下一组就好了。
  3. 但是我们知道,现在n非常的大。所以我们不可能全部遍历。这个时候我们用拉姆塞理论(原理看专栏)可以得出n>=6时,一定有一方可以成为三角形。
  4. 还有大佬用硬核做法,就是随便查找三条边,查到就输出yes就行了。因为yes的可能性很大,随便找节点遍历50w次(随机取样做法,超级佩服想到的大佬)
  5. 所以我们只要遍历比6小的可能性就好了。详情看代码~


拉姆塞理论

其实这个原理我也不会证明,我们先来说一下定义:
  • 用引例描述就是两个人可以彼此认识,也可以彼此不认识,人数大于或等于6时,则必定有3个人,他们一定彼此认识或彼此都不认识。
你可能会很懵,为什么呢?没事!我会告诉你,我也不知道为什么。orz

所以我们就用一个图例简单理解一下
  1. 我们可以看到,前三个图形都可以有方法无法产生三角形区域。
  2. 但是第四个六边形,一定会产生:我们现在红边已经构成了两个三角形,蓝边没有构成三角形,但是如果把任意红边换成蓝边,都一定会产生蓝色三角形。
  3. 所以结果就是:我们想拆红三角形,就会产生蓝色三角形。拆蓝色三角形,就会产生红色三角形。
  4. 差不多就是这样,理解一下~~~


AC代码

#include <iostream>
#include <cstring>
using namespace std;
//代码预处理区

const int MAX = 7;
int edge[MAX][MAX];//点与点之间的关系(1为有边)
//全局变量区

template<class T>inline void read(T& res);//整型快读函数
//函数预定义区

int main() {
    int T; read(T);
    while (T--) {
        int n, m; read(n); read(m);
        if (n >= 6) {
            for (int i = 0; i < m; i++) {
                int x, y; read(x); read(y);
            }
            printf("yes\n");
            continue;
        }
                //根据拉姆塞理论,n>=6一定有一方三条边可以构成三角形
        memset(edge, 0, sizeof(edge));
        for (int i = 1; i <= m; i++) {
            int x, y; read(x); read(y);
            edge[x][y] = edge[y][x] = 1;
        }
                //初始化edge数组
        int flag = 0;
        for (int i = 1; i <= n && !flag; i++)
            for (int j = i + 1; j <= n && !flag; j++)
                for (int k = j + 1; k <= n && !flag; k++)
                    if (edge[i][j] == edge[j][k] && edge[j][k] == edge[k][i])
                        flag = 1;
                //遍历查找是否有合适的点对
        if (flag) printf("yes\n");
        else printf("no\n");
    }
    return 0;
}
template<class T>inline void read(T& res) {
    char c; T flag = 1;
    while ((c = getchar()) < '0' || c > '9')
        if (c == '-')
            flag = -1;
    res = c - '0';
    while ((c = getchar()) >= '0' && c <= '9')
        res = res * 10 + c - '0';
    res *= flag;
}
//函数区