【Cf #290 C】Fox And Dinner(最大流)

如果要相邻两个数(a[i] >= 2)相加为质数,显然它们的奇偶性不同,也就是说一个圆桌(环)必须是偶环。

也就是答案的若干个环组成了一张二分图,其中以奇偶分色。

考虑每个点的度数一定为2,用最大流解决:

  1. 让源点向所有的奇数点连流量为2的边。
  2. 让所有的偶数点向汇点连流量为2的边。
  3. 当且仅当一组奇数和偶数相加为质数时,连一条流量为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 }
View Code

 

posted @ 2018-07-11 19:36  Dance_Of_Faith  阅读(214)  评论(0编辑  收藏  举报