1. 程式人生 > >2017CCPC秦皇島ZOJ 3988 Prime Set

2017CCPC秦皇島ZOJ 3988 Prime Set

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>

using namespace std;

#define N 2000010
#define inf 0x3f3f3f3f
int prime[N];
int num[3005];
vector<int>g[3005]
; int dx[3005]; int dy[3005]; int dis; int vis[3005]; int vm[3005]; int um[3005]; int n, k; int f[3005]; int d[3005]; void init() { memset(num, 0, sizeof(num)); memset(g, 0, sizeof(g)); for (int i = 0; i < 3005; i++) { g[i].clear(); } memset(vm, -1, sizeof(vm)); memset(um, -1, sizeof(um)); memset(f, -1, sizeof
(f)); } //模板 bool searchP() { queue<int>q; dis = inf; memset(dx, -1, sizeof(dx)); memset(dy, -1, sizeof(dy)); for (int i = 1; i <= n; i++) if (um[i] == -1) { q.push(i); dx[i] = 0; } while (!q.empty()) { int u = q.front(); q.pop(); if (dx[u]>dis) break; for (int
i = 0; i<g[u].size(); i++) { int v = g[u][i]; if (dy[v] == -1) { dy[v] = dx[u] + 1; if (vm[v] == -1) dis = dy[v]; else { dx[vm[v]] = dy[v] + 1; q.push(vm[v]); } } } } return dis != inf; } bool dfs(int u) { for (int i = 0; i<g[u].size(); i++) { int v = g[u][i]; if (!vis[v] && dy[v] == dx[u] + 1) { vis[v] = 1; if (vm[v] != -1 && dy[v] == dis) continue; if (vm[v] == -1 || dfs(vm[v])) { vm[v] = u; um[u] = v; return 1; } } } return 0; } int maxMatch() { int res = 0; while (searchP()) { memset(vis, 0, sizeof(vis)); for (int i = 1; i <= n; i++) if (um[i] == -1 && dfs(i)) res++; } return res; } //素數打表 void isPrime() { memset(prime, 0, sizeof(prime)); prime[0] = prime[1] = 1; for (int i = 2; i*i <= N; i++) { if (prime[i] == 0) { for (int j = i + i; j <= N; j += i) { prime[j] = 1; } } } return; } int main() { int cas; scanf("%d", &cas); isPrime(); while (cas--) { init(); int num_1 = 0; int num_11 = 0; scanf("%d%d", &n, &k); for (int i = 1; i <= n; i++) { scanf("%d", &num[i]); if (num[i] == 1) { num_1++; } } //建圖 for (int i = 1; i <= n; i++) { for (int j = i + 1; j <= n; j++) { int t = num[i] + num[j]; if (num[i] == 1 && num[j] == 1) { continue; } if (prime[t] == 0) { if (num[i] % 2 == 0) { g[i].push_back(j); } else { g[j].push_back(i); } } } } int ans = maxMatch(); int ans1 = 0; int num_111 = 0; memset(d, 0, sizeof(d)); //HK演算法中,um[i]==-1表示二分圖中的一側沒有匹配的點,vm[i]==-1表示另一側沒有匹配的點 for (int i = 1; i<=n; i++) { if (g[i].size() != 0) { if (um[i] == -1&&d[i]==0) { ans1++; d[i]++; if (num[i] == 1) { num_111++;//圖中不匹配1的個數 } } if (um[i] != -1 && num[i] == 1&&d[i]==0) { d[i]++; num_11++; //圖中匹配點1的個數 } for (int j = 0; j<g[i].size(); j++) { if (vm[g[i][j]] == -1&&d[g[i][j]]==0) { ans1++; d[g[i][j]]++; if (num[g[i][j]] == 1) { num_111++; } } if (vm[g[i][j]] != -1 && num[g[i][j]] == 1&& d[g[i][j]] == 0) { num_11++; d[g[i][j]]++; } } } } //分一條邊的貢獻和一個點的共享兩種情況 int y = 0; if (num_111+num_11 == 0) { y = num_1 / 2; ans1 += num_1-(num_1/2*2); } else { y = num_111 / 2; ans1 -= y * 2; } y = ans + y; if (k <= y) { printf("%d\n", min(n,2*k)); } else { printf("%d\n",2*y +min(ans1,(k-y))); } } return 0; }