/*
Double-connected vertex, double-connected edge, double-connected Odd Circle, classic question
Tle + wa n times, finally ac...
Question:
King Arthur wants to hold a knight meeting on the round-table. In order not to cause conflicts between the knights, but to make the topics of the meeting have satisfactory results, before each meeting, you must have the following requirements for the server guard attending the meeting:
1. Two servers that hate each other cannot sit directly in two adjacent locations;
2. The number of knights present at the meeting must be an odd number, so that all voting questions can be answered.
If a certain server guard is unable to attend all meetings (for example, the server guard hates all other servers), Arthur will force him out of the server for the sake of world peace.
Now we are given the number N of the server guard preparing to go to the meeting, and then the M-to-hate pair (which indicates that a certain two servers hate each other). We asked a few server guard who will never be able to hold the meeting.
Note: 1. The relationship between hate and hate must be bidirectional.
2. Because it is a round-table meeting, each server guard must have exactly two nearby servers. That is to say, each server's seat must have a server guard on both sides.
3. A server guard cannot have a meeting. That is to say, at least three servers can have a meeting.
Solution:
1. Read the question clearly. The requirement is "a few knights cannot form any circle with anyone "!! Here they are called "tragic Knight" first, and other people who can hold meetings are called "happy Knight"
2. Being able to sit next to each other means that there is no hate between the two. It is easy to think of a supplementary map that creates a hate relationship ~ G
3. In ~ G, the tragic server guard cannot form a ring with others, or they can only form an even ring with others. In other words, server guard can not only form a ring with others, but at least one of these rings (n> = 3 & N % 2! = 0.
4. The connected components have the following relationships with the odd circle:
(1) If some vertices in a dual-connected component are in a Odd Circle (that is, the dual-connected component contains odd circles), other vertices of the dual-connected component are in a certain odd circle;
(2) If a dual-connected component contains an odd circle, then he must not be a bipartite graph. This is a sufficient condition.
The first theorem is particularly important here. With this theorem, we can convert "Does server guard I exist in at least one odd circle" to "does the dual-connected component of server guard I have an odd circle"
5. tarjan can calculate the dual-connected component. Each time it conforms to dfn [u] <= low [v], a dual-connected component is generated, therefore, we need to judge whether the dual-Connected Component exists in an odd circle every time a dual-connected component is generated. If so, all the knights in the dual-connected component are eligible for a meeting.
6. the odd circle is judged to be stained. Many people on the internet use the bipartite graph to dye it. I think it is wrong, but the data on this question is weak, through ===, Theorem 1 can be better understood.
7. this question can be done with double or double thinking. I use double thinking. The online shopping is mostly about double thinking, but the difference is not big. I need to deal with a little detail in double thinking.
For example, when the current dual-connected block is extracted from the stack, the splitting point cannot be removed from the stack, because the splitting point can belong to multiple dual-connected blocks.
At the beginning of TLE, Huang Shu said, "You can't do the dual-side questions by clicking here ~~
8. In the background, dyeing is the key... A lot of details, such as understanding Theorem 1 before writing well. If not, a bipartite graph will be written. If you want to initialize color, yes,
The problem that xiaoyou wrote is very good. Aside from a few points of attention, it should be noted in the comments.
Http://blog.csdn.net/lyy289065406/article/details/6756821
This person's approach is the same as mine: http://blog.csdn.net/tsaid/article/details/6895808
*/
# Include <algorithm> # include <stdio. h> # include <stack> # include <string. h> using namespace STD; # define maxn 1005 # define maxm 1000005 struct edge {int V, next;} edge [maxm * 2]; int low [maxn], dfn [maxn], head [maxn], result [maxm], color [maxn]; bool path [maxn] [maxn], Label [maxn], visit [maxm * 2], Yes [maxn], in_stack [maxn]; int n, m, edge_num, index; stack <int> S; // result [] records the current dual-connection block's knight color [] for dyeing // Label [I] records I yes No eligible meeting Yes [I] indicates whether the current dual-connected block contains the server guard I visit [K]. Because it is an undirected graph, it is used to determine whether the edge is reused void Init () {edge_num = 0; index = 1; memset (Head,-1, sizeof (head); memset (visit, false, sizeof (visit); memset (path, false, sizeof (PATH); memset (dfn, 0, sizeof (dfn); memset (low, 0, sizeof (low); memset (Label, false, sizeof (Label); memset (color, 0, sizeof (color); memset (yes, false, sizeof (yes); memset (in_stack, false, sizeof (in_stack )); While (! S. empty () s. pop ();} void add_edge (int u, int v) {edge [edge_num]. V = V; edge [edge_num]. next = head [u]; head [u] = edge_num ++;} bool dye (int u, int C, int F) // {bool flag = true; If (color [u]) return color [u]! = C; color [u] = C; For (int K = head [u]; k! =-1; k = edge [K]. Next) {int v = edge [K]. V; If (! Yes [v] | V = f) continue; If (dye (v, 3-C, u) return true; // return true directly at the beginning, without the following else, the function returns false directly at the end, but when it is a leaf node, the error else flag = false;} // color [u] = 0; // if none of them are successful, the mark will be erased because it is DFS ///??? // It seems that you don't need .. Well understand Theorem 1 return flag;} void judge (int u, int v) {int sum = 0, x; memset (yes, false, sizeof (yes )); do {x = S. top (); S. pop (); Result [Sum ++] = x; Yes [x] = true; in_stack [x] = false;} while (X! = V); // do not output the final u from the stack, because the cut point may belong to multiple dual-connected blocks. Result [Sum ++] = u; Yes [u] = true; // This is the last modification point .... Finally ac... // Printf ("$"); // For (INT I = 0; I <sum; I ++) printf ("% d ", result [I]); // printf ("\ n"); For (INT I = 0; I <sum; I ++) color [result [I] = 0; // erase the mark. // put it behind it. Of course it will be wa !! If (sum <3 |! Dye (result [0], 1,-1) return; // printf ("$"); // For (INT I = 0; I <sum; I ++) printf ("% d (% d)", result [I], color [result [I]); // printf ("\ n "); for (INT I = 0; I <sum; I ++) Label [result [I] = true; // mark these persons with meeting qualifications} void Tarjan (INT U) {dfn [u] = low [u] = index ++; S. push (U); in_stack [u] = true; For (int K = head [u]; k! =-1; k = edge [K]. Next) if (! Visit [k]) {visit [k] = visit [k ^ 1] = true; int v = edge [K]. V; If (! Dfn [v]) {Tarjan (V); low [u] = min (low [u], low [v]); if (low [v]> = dfn [u]) {judge (u, v); // when a cut point is encountered, determine whether the current dual-connected component has an odd circle.} Else if (in_stack [v]) low [u] = min (low [u], dfn [v]); // Why Should I judge whether it is in_stack?} Int work () {int X, Y; Init (); While (M --) {scanf ("% d", & X, & Y ); if (path [x] [Y]) continue; path [x] [Y] = path [y] [x] = true;} For (INT I = 1; I <= N; I ++) for (Int J = I + 1; j <= N; j ++) if (path [I] [J] = false) {// not handled properly here, TLE many times. Be sure to add (I, j), (J, I) to the storage edge array, otherwise, the/visit [k] = visit [k ^ 1] = true in the Tarjan is incorrect. I didn't notice add_edge (I, j); add_edge (J, I );} for (INT I = 1; I <= N; I ++) if (! Dfn [I]) Tarjan (I); int sum = 0; For (INT I = 1; I <= N; I ++) sum + = (Label [I] = false); // For (INT I = 1; I <= N; I ++) if (Label [I] = false) printf ("# % d \ n", I); // printf ("\ n "); // printf ("=============================\ N"); // For (INT I = 1; I <= N; I ++) {// For (int K = head [I]; k! =-1; k = edge [K]. next) {// printf ("-- % d \ n", I, edge [K]. v); //} // printf ("\ n"); //} return sum;} int main () {While (scanf ("% d ", & N, & M), N + M) printf ("% d \ n", work (); Return 0 ;}