Codeforces 512C Fox And Dinner odd And even graph network flow, codeforces512c
Question link: Click the open link
Question:
Given n people and their weights.
Let people sit on any round table so that any two adjacent human rights values are prime numbers, and a table contains at least three people.
Output The number of tables and the number of persons sitting at each table (output any specific scheme)
Ideas:
First, all human weights are greater than or equal to 2, which means that the prime number in combination must be an odd number.
Odd Number = odd number + even number. Therefore, the people on the table must be odd and even, and the number of people in a table is even (that is, n must be an even number, half is an odd number, and half is an even number)
From top: select two even numbers for an odd number and two odd numbers for an even number.
So we can get a two-part graph. The X set is an odd number, and the Y set is an even number.
Network stream:
Odd connected source point, flow = 2
Even number of connected points, flow = 2
If (odd + even = Prime)
An odd number connects an edge of flow = 1 to an even number.
When the stream is full, it indicates there is a solution.
.
When outputting the scheme, place the connected block at a table.
# Pragma comment (linker, "/STACK: 1024000000,1024000000") # include <stdio. h> # include <iostream> # include <algorithm> # include <queue> # include <cstring> # include <vector> # include <set> # include <cmath> using namespace std; # define inf 1073741824 # define N 500 # define M 100100 // N is the number of points M is the number of sides struct Edge {int from, to, cap, nex ;} edge [M * 2]; // bidirectional edge. Note that this template is effective at the same time as the edge of the last vertex rather than removing the int head [N], tot; // two to be initialized-1 and 0 void add (int u, int V, int cap, int rw = 0) {// reverse arc should be added to the network stream, that is, if u-> v is 10, v-> u is-10 Edge E = {u, v, cap, head [u]}; edge [tot] = E; head [u] = tot ++; Edge E2 = {v, u, rw, head [v]}; // if it is an undirected edge, the rw parameter value is the same as that of cap (add (u, v, cap, cap )), if there is a directed edge, rw is not written (that is, add (u, v, cap);) edge [tot] = E2; head [v] = tot ++ ;} int dis [N], cur [N]; // dis [I] indicates the distance from the I point to the starting point. cur [I] indicates the edge being considered in the edge connected to the I point. Edge optimization is not considered. The used vertex is initialized to headbool. vis [N]; bool BFS (int Start, int End) {// run the shortest memse T (vis, 0, sizeof (vis); memset (dis,-1, sizeof (dis); queue <int> Q; Q. push (Start); dis [Start] = 0; vis [Start] = 1; while (! Q. empty () {int u = Q. front (); Q. pop (); for (int I = head [u]; I! =-1; I = edge [I]. nex) {Edge E = edge [I]; if (! Vis [E. to] & E. cap> 0) {vis [E. to] = true; dis [E. to] = dis [u] + 1; if (E. to = End) return true; Q. push (E. to) ;}}return false;} int DFS (int x, int a, int End) {// The current inbound traffic x is a traffic a is the minimum value of all edge weights in the outbound traffic if (x = End | a = 0) return; int flow = 0, f; // flow indicates the flow from point x to all points below. The maximum traffic is for (int & I = cur [x]; I! =-1; I = edge [I]. nex) {Edge & E = edge [I]; if (dis [x] + 1 = dis [E. to] & (f = DFS (E. to, min (a, E. cap), End)> 0) {E. cap-= f; edge [I ^ 1]. cap + = f; // flow + = f; a-= f; if (a = 0) break ;}} return flow;} must be removed from the reverse side ;} int Dinic (int Start, int End) {int flow = 0; while (BFS (Start, End) {// memcpy (cur, head, sizeof (head); // copy the head array to flow + = DFS (Start, inf, End);} return flow;} void init (){ Memset (head,-1, sizeof head); tot = 0;} int prime [10000], primenum; // math has primenum prime numbers. h set <int> p; void PRIME (int Max_Prime) {p. clear (); primenum = 0; prime [primenum ++] = 2; for (int I = 3; I <= Max_Prime; I ++ = 2) for (int j = 0; j <primenum; j ++) if (I % prime [j] = 0) break; else if (prime [j]> sqrt (double) I) | j = primenum-1) {prime [primenum ++] = I; break ;} for (int I = 0; I <primenum; I ++) P. insert (prime [I]);} int a [N], n; vector <int> G [N]; int top; bool Vis [N]; void dfs (int u, vector <int> & x) {Vis [u] = 1; x. push_back (u); for (int I = head [u]; ~ I; I = edge [I]. nex) {int v = edge [I]. to; if (Vis [v]) continue; if (a [u] & 1) {if (edge [I]. cap! = 1) {edge [I]. cap ++; dfs (v, x) ;}} else {if (edge [I]. cap) {edge [I]. cap --; dfs (v, x) ;}}} int main () {PRIME (20000); while (cin >>n) {for (int I = 0; I <n; I ++) cin> a [I]; if (n & 1) {puts ("Impossible"); continue;} init (); int from = n, to = n + 1; Vis [from] = Vis [to] = 1; for (int I = 0; I <n; I ++) {G [I]. clear (); Vis [I] = 0; if (a [I] & 1) add (from, I, 2); else add (I, to, 2 ); for (int j = 0; j <n; j ++) if (p. count (a [I] + a [j]) {if (a [I] & 1) add (I, j, 1 );}} int all = Dinic (from, to); if (all = n) {top = 0; for (int I = 0; I <n; I ++) if (Vis [I] = 0) {dfs (I, G [top ++]);} printf ("% d \ n", top ); for (int I = 0; I <top; I ++) {printf ("% d", G [I]. size (); for (int j = 0; j <G [I]. size (); j ++) printf ("% d", G [I] [j] + 1); puts ("");}} else puts ("Impossible");} return 0 ;}