而是Div2的最后一题,当时打比赛的时候还不会最大流。自己能够把它写出来然后1A还是很开心的。
题意:
有n个不小于2的整数,现在要把他们分成若干个圈。在每个圈中,数字的个数不少于3个,而且相邻的两个数之和是质数。
分析:
因为每个数都不小于2,所以相加得到的质数一定是奇数,那么在某个圈中,一定是奇偶相间的。
也就是 奇数相邻的两个数是偶数,偶数相邻的两个数是奇数。
所以一个圈中的数字一定是偶数个,所有的输入中也必须是偶数和奇数的个数相同才可能有解。
这转化为了二分图匹配,其中X是奇数,Y是偶数,如果X和Y中的两个数加起来是质数,则连一条容量为1的边。
因为每个奇数的两边是偶数,所以将X中的点与源点连一条容量为2的边。
同样地,将Y中的点与汇点连一条容量为2的边。
求一次最大流,如果满载也就是流量为n的话,说明有解。
输出解:可以根据求解最大流的时候,找到的路径,再建一个图,然后DFS找环。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 200 + 10; 6 const int INF = 1000000000; 7 8 struct Edge 9 { 10 int from, to, cap, flow; 11 Edge(int u, int v, int c, int f): from(u), to(v), cap(c), flow(f) {} 12 }; 13 14 struct EdmondsKarp 15 { 16 int n, m; 17 vector<Edge> edges; 18 vector<int> G[maxn]; 19 int a[maxn]; //可改进量 20 int p[maxn]; //上一条弧 21 22 void Init(int n) 23 { 24 for(int i = 0; i < n; ++i) G[i].clear(); 25 edges.clear(); 26 } 27 28 void AddEdge(int from, int to, int cap) 29 { 30 edges.push_back(Edge(from, to, cap, 0)); 31 edges.push_back(Edge(to, from, 0, 0)); 32 m = edges.size(); 33 G[from].push_back(m-2); 34 G[to].push_back(m-1); 35 } 36 37 int MaxFlow(int s, int t) 38 { 39 int flow = 0; 40 for(;;) 41 { 42 memset(a, 0, sizeof(a)); 43 queue<int> Q; 44 Q.push(s); 45 a[s] = INF; 46 while(!Q.empty()) 47 { 48 int x = Q.front(); Q.pop(); 49 for(int i = 0; i < G[x].size(); ++i) 50 { 51 Edge& e = edges[G[x][i]]; 52 if(!a[e.to] && e.cap > e.flow) 53 { 54 a[e.to] = min(a[x], e.cap - e.flow); 55 p[e.to] = G[x][i]; 56 Q.push(e.to); 57 } 58 } 59 if(a[t]) break; 60 } 61 if(!a[t]) break; 62 for(int u = t; u != s; u = edges[p[u]].from) 63 { 64 edges[p[u]].flow += a[t]; 65 edges[p[u]^1].flow -= a[t]; 66 } 67 flow += a[t]; 68 } 69 return flow; 70 } 71 }g; 72 73 int a[maxn], odd[maxn], even[maxn], p1, p2; 74 vector<int> G[maxn], ans[maxn]; 75 const int maxp = 20000; 76 bool prime[maxp + 10], vis[maxn]; 77 78 void prime_table() 79 { 80 int m = sqrt(maxp + 0.5); 81 for(int i = 2; i <= m; ++i) if(!prime[i]) 82 for(int j = i*i; j <= maxp; j += i) prime[j] = true; 83 } 84 85 void find_circle(int cnt, int u) 86 { 87 ans[cnt].push_back(u); 88 vis[u] = true; 89 for(int i = 0; i < G[u].size(); ++i) 90 { 91 int v = G[u][i]; 92 if(!vis[v]) find_circle(cnt, v); 93 } 94 } 95 96 int main() 97 { 98 //freopen("in.txt", "r", stdin); 99 100 int n; 101 scanf("%d", &n); 102 g.Init(n+2); 103 for(int i = 1; i <= n; ++i) 104 { 105 scanf("%d", &a[i]); 106 if(a[i] & 1) odd[p1++] = i; 107 else even[p2++] = i; 108 } 109 if(p1 != p2) { puts("Impossible"); return 0; }//奇数和偶数个数不同 110 111 for(int i = 0; i < p1; ++i) 112 { 113 g.AddEdge(0, odd[i], 2); 114 g.AddEdge(even[i], n+1, 2); 115 } 116 117 prime_table(); 118 for(int i = 0; i < p1; ++i) 119 for(int j = 0; j < p1; ++j) 120 if(!prime[ a[odd[i]] + a[even[j]] ]) 121 g.AddEdge(odd[i], even[j], 1); 122 123 int flow = g.MaxFlow(0, n+1); 124 if(flow != n) { puts("Impossible"); return 0; } 125 126 for(int i = 0; i < g.edges.size(); ++i) 127 {//为了寻找路径,建一个新图 128 Edge& e = g.edges[i]; 129 if(e.cap == 1 && e.flow == 1) 130 { 131 G[e.from].push_back(e.to); 132 G[e.to].push_back(e.from); 133 } 134 } 135 136 int cnt = 0; 137 for(int i = 1; i <= n; ++i) if(!vis[i]) find_circle(cnt++, i); 138 139 printf("%d ", cnt); 140 for(int i = 0; i < cnt; ++i) 141 { 142 printf("%d %d", ans[i].size(), ans[i][0]); 143 for(int j = 1; j < ans[i].size(); ++j) printf(" %d", ans[i][j]); 144 puts(""); 145 } 146 147 return 0; 148 }