题意:一个集合内有n个数字,如果一个等式中 a * b = c 中 b是质数,说明a和c质数相关否则质数无关,问这个集合的子集满足两两之间都质数无关的最大子集。
题解:比赛时没有做出来,参考大神的做法,这是道二分图匹配中找最大独立集。如果是质数相关的两个点就添加一条边,独立集中任意两点不存在边。
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
const int N = 1005;
const int M = 1000010;
int n, s[N], flag[500005], cnt, head[N], vis[N], link[N], res;
struct Edge {
int v, next;
}e[M];
bool dfs(int u) {
for (int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if (!vis[v]) {
vis[v] = 1;
if (link[v] == -1 || dfs(link[v])) {
link[v] = u;
return true;
}
}
}
return false;
}
void add(int u, int v) {
e[cnt].v = v;
e[cnt].next = head[u];
head[u] = cnt++;
}
void init() {
for (int i = 2; i < 500001; i++)
for (int j = i + i; j < 500001; j += i)
if (!flag[j])
flag[j] = 1;
}
int main() {
int t, cas = 1;
init();
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d", &s[i]);
res = cnt = 0;
memset(head, -1, sizeof(head));
memset(link, -1, sizeof(link));
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
if (s[i] != s[j]) {
if (s[i] % s[j] != 0 && s[j] % s[i] != 0)
continue;
int temp = s[i] > s[j] ? s[i] / s[j] : s[j] / s[i];
if (!flag[temp])
add(i, j);
}
}
for (int i = 0; i < n; i++) {
memset(vis, 0, sizeof(vis));
if (dfs(i))
res++;
}
printf("Case #%d: %d\n", cas++, (2 * n - res) / 2);
}
return 0;
}