PTA volume chart (25 points) (bipartite chart + bfs + combined search)

7-10 Scrolls (25 points)

As an excellent student of an excellent university, Xiaow must live in an environment of extremely internal examination: every big report, every final exam, every homework...

In a certain class of big x, after the teacher divided the grouping tasks, Xiao W was surprised to find that the students in the class were automatically divided into groups. Little w, who is proficient in discrete mathematics, abstracts the students in the paper into points, and then it is impossible to divide the students into a group to connect the edges. Little w found that this picture has the following properties:

The graph has n nodes, and the n nodes on the graph can be divided into two sets A and B;

  1. A∩B=∅

  2. The points in the set A have no edges

  3. The points in the set B have no edges

Xiaow called such a picture a scroll picture. The problem came. Xiaow suddenly had a lot of weird pictures. Please judge which ones are scroll pictures and which ones are not.

Input format:

Note that there are multiple sets of data in this question.

The first line of each group of test data will read a number t (1≤t≤20), which represents the number of groups of test data.

After t groups of data, read two numbers in the first row of each group of data n,m(1≤n≤10^​5​​ ,1≤m≤min(​2​n⋅(n−1)​​ ,200000)), which means that the graph is composed of n points and m edges.

In the next m lines, each line has two integers u, v (1≤u, v≤n), u≠v, which represents an edge between the points u and v.

The graph given by the data guarantee is a simple graph, that is, no heavy edges and self-loops

Output format:

For each picture of each group of samples, if it is a roll picture, output Ye5!juantu

Otherwise, output N0!

Input sample:

Here is a set of inputs. E.g:

2
3 3
1 2
2 3
3 1
3 2
1 2
1 3

Sample output:

The corresponding output is given here. E.g:

N0!
Ye5!juantu

prompt

For example 1, the first picture is:
Insert picture description here
cannot find such two point sets A and B, so it is not a roll picture

The second picture: the
Insert picture description here
red dots and blue dots constitute the point set shown in the title, so it can form a scroll diagram.

Problem solving

This question uses the chain storage structure of graphs. The input graph is not necessarily a connected graph. Therefore, it is necessary to use the union search set to perform bfs search on the graphs of each set. When there are odd cycles in the graph, it means that it is not a bipartite graph, bfs When searching, mark each node's bfs tree level. When it traverses to a node that has not been visited, visit and mark it. When it is a visited node, it means that there is a loop, and if the current node is with the visited node The number of layers of the nodes is the same, which means that it is an odd ring, which is not a bipartite graph.
By drawing the structure of a simple graph with fewer vertices, observe and summarize the rules:
Insert picture description here

Code

#include <algorithm>  //7-10 卷图 (25分)
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 1e5 + 2;
bool vis[maxn];
int Set[maxn];

//找出所有的环, 如果存在奇数顶点构成的环, 则不是卷图 (自己列举几个简单图)

/*复习一下指针的链式存储, C语言数据结构*/
struct AdjVNode {
    
      //邻接链表的链
    AdjVNode *Next;
    int adjV;
};
typedef struct VNode {
    
    
    AdjVNode *FirstEdge;  //无权图
    int k;                //记录bfs树的层数
} AdjVList[maxn];
typedef struct GNode {
    
    
    int Nv, Ne;
    AdjVList L;
} * LGraph;
typedef struct ENode {
    
    
    int v1, v2;
} * Edge;

void InsertEdge(LGraph G, Edge E) {
    
      //给图插入边
    AdjVNode *A;
    A = new AdjVNode, A->adjV = E->v2;
    A->Next = G->L[E->v1].FirstEdge, G->L[E->v1].FirstEdge = A;

    A = new AdjVNode, A->adjV = E->v1;
    A->Next = G->L[E->v2].FirstEdge, G->L[E->v2].FirstEdge = A;
}

LGraph CreateGraph(int Nv, int Ne) {
    
      //新建图
    LGraph G = new GNode();
    G->Nv = Nv, G->Ne = Ne;
    return G;
}

void DestroyGraph(LGraph G) {
    
      //删除图, 释放内存
    AdjVNode *A;
    for (int i = 1; i <= G->Nv; i++)
        while (G->L[i].FirstEdge) {
    
    
            A = G->L[i].FirstEdge;
            G->L[i].FirstEdge = A->Next;
            delete A;
        }
    delete G;
    G = NULL;
}

bool bfs(LGraph G, int start) {
    
    
    queue<int> q;
    q.push(start);
    G->L[start].k = 1;
    vis[start] = true;
    AdjVNode *A;
    while (!q.empty()) {
    
    
        int v = q.front();  //当前节点
        int k = G->L[v].k;
        q.pop();
        A = G->L[v].FirstEdge;
        while (A) {
    
    
            if (!vis[A->adjV]) {
    
      //如果访问到新节点, 入队
                vis[A->adjV] = true;
                q.push(A->adjV);
                G->L[A->adjV].k = k + 1;
            } else if (k == G->L[A->adjV].k) {
    
    
                //如果是已访问的结点, 说明找到环路了,而如果是同一层说明是奇数环
                return false;
            }
            A = A->Next;
        }
    }
    return true;
}
/*并查集*/
int FindSet(int x) {
    
    
    if (Set[x] < 0) return x;
    return Set[x] = FindSet(Set[x]);
}
void Union(int r1, int r2) {
    
    
    if (r1 == r2) return;
    if (Set[r1] < Set[r2])
        Set[r1] += Set[r2], Set[r2] = r1;
    else
        Set[r2] += Set[r1], Set[r1] = r2;
}

int main() {
    
    
    int T, n, m;
    cin >> T;
    LGraph G = NULL;
    vector<int> vv;
    while (T--) {
    
    
        memset(vis, false, sizeof(vis));
        memset(Set, -1, sizeof(Set));
        vv.clear();

        scanf("%d %d", &n, &m);
        G = CreateGraph(n, m);
        Edge E = new ENode();
        for (int i = 0; i < m; i++) {
    
    
            scanf("%d %d", &E->v1, &E->v2);
            Union(FindSet(E->v1), FindSet(E->v2));
            InsertEdge(G, E);
        }

        /*求解判断*/
        for (int i = 1; i <= n; i++)  //将所有集合的根加入数组记录
            if (Set[i] < 0) vv.push_back(i);
        bool bo = true;
        for (int i = 0; i < vv.size(); i++) {
    
    
            int start = vv[i];
            bo = bfs(G, start);
            if (!bo) {
    
    
                printf("N0!\n");
                break;
            } else if (i == vv.size() - 1)  //如果bo = true, 且是最后一个
                printf("Ye5!juantu\n");
        }

        delete E;
        DestroyGraph(G);
    }

    system("pause");
    return 0;
}

Guess you like

Origin blog.csdn.net/qq_45349225/article/details/109357260