【Cf #290 C】Fox And Dinner(最大流)
如果要相邻两个数(a[i] >= 2)相加为质数,显然它们的奇偶性不同,也就是说一个圆桌(环)必须是偶环。
也就是答案的若干个环组成了一张二分图,其中以奇偶分色。
考虑每个点的度数一定为2,用最大流解决:
- 让源点向所有的奇数点连流量为2的边。
- 让所有的偶数点向汇点连流量为2的边。
- 当且仅当一组奇数和偶数相加为质数时,连一条流量为1的边。
可以证明,如果最大流小于n,那就不存在解,否则一定存在若干个边数大于2的偶环,使得所有点只出现在一个环里,最后Dfs找出环即可。
$ \bigodot $ 技巧&套路:
- 根据奇偶性或网格图黑白染色,想到建立二分图。
- 最大流的模型。
1 #include <cstdio> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 6 const int N = 305, M = 100005; 7 8 int n, s, t, tot, a[N], vis[N], lc[N], rc[N], ln, rn; 9 int ntp[20005]; 10 std::vector<int> an[N]; 11 12 void Init() { 13 ntp[1] = 1; 14 for (int i = 2; i <= 20000; ++i) if (!ntp[i]) { 15 for (int j = i * i; j <= 20000; j += i) { 16 ntp[j] = 1; 17 } 18 } 19 } 20 21 namespace GR { 22 int yun = 1, cur[N], las[N], to[M << 1], pre[M << 1], fl[M << 1]; 23 int h[N], gap[N]; 24 inline void Add(int a, int b, int c) { 25 to[++yun] = b; fl[yun] = c; pre[yun] = las[a]; las[a] = yun; 26 to[++yun] = a; fl[yun] = 0; pre[yun] = las[b]; las[b] = yun; 27 } 28 int Isap(int x, int flo, int usd = 0) { 29 if (x == t) return flo; 30 for (int i = cur[x]; i; i = pre[i]) if (fl[i] > 0 && h[to[i]] + 1 == h[x]) { 31 int f = Isap(to[i], std::min(flo, fl[i])); 32 usd += f; fl[i] -= f; fl[i ^ 1] += f; 33 if (fl[i] > 0) cur[x] = i; 34 if (usd == flo) return flo; 35 } 36 if (gap[h[x]] == 1) h[s] = t + 9; 37 --gap[h[x]]; ++gap[++h[x]]; 38 cur[x] = las[x]; 39 return usd; 40 } 41 int Max_flow(int re = 0) { 42 memset(h, 0, sizeof h); 43 memset(gap, 0, sizeof gap); 44 for (; h[s] < t + 9; ) re += Isap(s, 1e9); 45 return re; 46 } 47 } 48 49 void Build() { 50 s = n + 1; t = n + 2; 51 for (int i = 1; i <= n; ++i) { 52 if (a[i] & 1) { 53 lc[++ln] = i; GR::Add(s, i, 2); 54 } else { 55 rc[++rn] = i; GR::Add(i, t, 2); 56 } 57 } 58 for (int i = 1; i <= ln; ++i) { 59 for (int j = 1; j <= rn; ++j) { 60 if (!ntp[a[lc[i]] + a[rc[j]]]) { 61 GR::Add(lc[i], rc[j], 1); 62 } 63 } 64 } 65 } 66 67 void Dfs(int gr, int x) { 68 an[gr].push_back(x); 69 vis[x] = 1; 70 for (int i = GR::las[x]; i; i = GR::pre[i]) { 71 int v = GR::to[i]; 72 if (vis[v] || v == s || v == t) continue; 73 if (((~i & 1) && GR::fl[i] == 0) || ((i & 1) && GR::fl[i] == 1)) { 74 Dfs(gr, v); 75 } 76 } 77 } 78 79 int main() { 80 Init(); 81 scanf("%d", &n); 82 for (int i = 1; i <= n; ++i) { 83 scanf("%d", &a[i]); 84 } 85 Build(); 86 87 int ans = GR::Max_flow(); 88 if (ans != n) { 89 puts("Impossible"); return 0; 90 } 91 for (int i = 1; i <= n; ++i) { 92 if (!vis[i]) Dfs(++tot, i); 93 } 94 printf("%d\n", tot); 95 for (int i = 1; i <= tot; ++i) { 96 printf("%d ", (int)an[i].size()); 97 for (int j = 0; j < (int)an[i].size(); ++j) { 98 printf("%d ", an[i][j]); 99 } 100 putchar('\n'); 101 } 102 103 return 0; 104 }