G - Erasing Prime Pairs (atcoder.jp)
有 n(n <= 100)种互不相同的数,分别是 \(A[i]\) (<=1e7), 每个有 \(B[i]\) 个
每次可以任意取两个数,如果相加是素数就消去这两个数,求最多操作次数
思路一、
思路二、
对于每个点都拆成入点和出点(解决了两个相同的数相加构成素数的情况),直接跑最大流,结果除以二即可
#include <bits/stdc++.h> #define itn int #define int long long #define endl "\n" #define PII pair<int, int> using namespace std; const int N = 1010; const int M = 2e7 + 10; const itn inf = 0x3f3f3f; const int mod = 998244353; // const int mod = 1e9 + 7; int n, m, s, t; struct Edge { int from, to, cap, flow; Edge(int f, int t, int c, int fl) { from = f; to = t; cap = c; flow = fl; } }; struct Dinic { int n, m, s, t; //结点数,边数(包括反向弧),源点编号和汇点编号 vector<Edge> edges; //边表。edge[e]和edge[e^1]互为反向弧 vector<int> G[N]; //邻接表,G[i][j]表示节点i和第j条边在e数组中的序号 bool vis[N]; // BFS使用 int d[N]; //从起点到i的距离 int cur[N]; //当前弧下标 void clear_all(int n) { for (int i = 0; i < n; i++) G[i].clear(); edges.clear(); } void clear_flow() { int len = edges.size(); for (int i = 0; i < len; i++) edges[i].flow = 0; } void add_edge(int from, int to, int cap) { edges.push_back(Edge(from, to, cap, 0)); edges.push_back(Edge(to, from, 0, 0)); m = edges.size(); G[from].push_back(m - 2); G[to].push_back(m - 1); } bool BFS() { memset(vis, 0, sizeof(vis)); queue<int> q; q.push(s); d[s] = 0; vis[s] = 1; while (!q.empty()) { int x = q.front(); q.pop(); int len = G[x].size(); for (int i = 0; i < len; i++) { Edge& e = edges[G[x][i]]; if (!vis[e.to] && e.cap > e.flow) { vis[e.to] = 1; d[e.to] = d[x] + 1; q.push(e.to); } } } return vis[t]; } int DFS(int x, int a) { if (x == t || a == 0) return a; int flow = 0, f, len = G[x].size(); for (int& i = cur[x]; i < len; i++) { Edge& e = edges[G[x][i]]; if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) { e.flow += f; edges[G[x][i] ^ 1].flow -= f; flow += f; a -= f; if (a == 0) break; } } return flow; } int maxflow(int s, int t) { this->s = s; this->t = t; int flow = 0; while (BFS()) { memset(cur, 0, sizeof(cur)); flow += DFS(s, inf); } return flow; } int mincut() { // call this after maxflow int ans = 0; int len = edges.size(); for (int i = 0; i < len; i++) { Edge& e = edges[i]; if (vis[e.from] && !vis[e.to] && e.cap > 0) ans++; } return ans; } void reduce() { int len = edges.size(); for (int i = 0; i < len; i++) edges[i].cap -= edges[i].flow; } } dinic; bool vis[M], isprime[M]; void init() { for (int i = 2; i <= M; i++) { if (vis[i]) continue; isprime[i] = 1; for (int j = i + i; j <= M; j += i) vis[j] = 1; } } int a[N], b[N]; void solve() { itn n; cin >> n; init(); int S = 0, T = 2 * n + 1; for (int i = 1; i <= n; i++) { cin >> a[i] >> b[i]; dinic.add_edge(S, i, b[i]); dinic.add_edge(i + n, T, b[i]); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (isprime[a[i] + a[j]]) dinic.add_edge(i, j + n, 1e18); } } cout << dinic.maxflow(S, T) / 2 << endl; } signed main() { ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0); cout << fixed << setprecision(12); solve(); return 0; }