#1158 : 质数相关
时间限制:2000ms
单点时限:1000ms
内存限制:256MB
描述
两个数a和 b (a<b)被称为质数相关,是指a × p = b,这里p是一个质数。一个集合S被称为质数相关,是指S中存在两个质数相关的数,否则称S为质数无关。如{2, 8, 17}质数无关,但{2, 8, 16}, {3, 6}质数相关。现在给定一个集合S,问S的所有质数无关子集中,最大的子集的大小。
输入
第一行为一个数T,为数据组数。之后每组数据包含两行。
第一行为N,为集合S的大小。第二行为N个整数,表示集合内的数。
输出
对于每组数据输出一行,形如"Case #X: Y"。X为数据编号,从1开始,Y为最大的子集的大小。
数据范围
1 ≤ T ≤ 20
集合S内的数两两不同且范围在1到500000之间。
小数据
1 ≤ N ≤ 15
大数据
1 ≤ N ≤ 1000
样例输入
3
5
2 4 8 16 32
5
2 3 4 6 9
3
1 2 3
样例输出
Case #1: 3
Case #2: 3
Case #3: 2
题目链接:http://hihocoder.com/problemset/problem/1158
题目分析:求二分图最大独立集,点权-最大匹配(网络流最小割)=最大独立集
建图方法:把素数分解时素因子都为奇数的数作为二分图的一边,另一边为左边数字质数相关的数
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <cmath> using namespace std; int const MAX = 500005; int const MAXN = 3000005; int const INF = 0x7fffffff; int p[MAX], a[1005]; bool prime[MAX]; int gap[MAXN], pre[MAXN], head[MAXN], d[MAXN], cur[MAXN]; int e_cnt, n; int src, sink; void get_prime() { memset(prime, true, sizeof(prime)); prime[1] = false; for(int i = 2; i <= sqrt(500000); i++) if(prime[i]) for(int j = i + i; j <= 500000; j += i) prime[j] = 0; } struct EDGE { int to, cap, flow, next; }e[MAXN]; void Add_Edge(int u, int v, int cap) { e[e_cnt].to = v; e[e_cnt].cap = cap; e[e_cnt].flow = 0; e[e_cnt].next = head[u]; head[u] = e_cnt ++; e[e_cnt].to = u; e[e_cnt].cap = 0; e[e_cnt].flow = 0; e[e_cnt].next = head[v]; head[v] = e_cnt ++; } void BFS(int t) { queue <int> Q; memset(gap, 0, sizeof(gap)); memset(d, -1, sizeof(d)); d[t] = 0; Q.push(t); while(!Q.empty()) { int v = Q.front(); Q.pop(); gap[d[v]] ++; for(int i = head[v]; i != -1; i = e[i].next) { int u = e[i].to; if(d[u] == -1) { d[u] = d[v] + 1; Q.push(u); } } } } int ISAP(int s, int t) { BFS(t); int ans = 0, u = s, flow = INF; memcpy(cur, head, sizeof(cur)); while(d[s] < e_cnt) { int i = cur[u]; for(; i != - 1; i = e[i].next) { int v = e[i].to; if(e[i].cap > e[i].flow && d[u] == d[v] + 1) { u = v; pre[v] = i; flow = min(flow, e[i].cap - e[i].flow); if(u == t) { while(u != s) { int j = pre[u]; e[j].flow += flow; e[j ^ 1].flow -= flow; u = e[j ^ 1].to; } ans += flow; flow = INF; } break; } } if(i == -1) { if(-- gap[d[u]] == 0) break; int mi = e_cnt - 1; cur[u] = head[u]; for(int j = head[u]; j != -1; j = e[j].next) if(e[j].cap > e[j].flow) mi = min(mi, d[e[j].to]); d[u] = mi + 1; gap[d[u]] ++; if(u != s) u = e[pre[u] ^ 1].to; } } return ans; } int main() { get_prime(); p[1] = 0; for(int i = 1; i <= 500000; i++) for(int j = 1; j <= 500000 / i; j++) if(prime[j]) p[i * j] = 1 - p[i]; int T; scanf("%d", &T); for(int ca = 1; ca <= T; ca++) { e_cnt = 0; memset(head, -1, sizeof(head)); printf("Case #%d: ", ca); scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); src = 0; sink = n + 1; for(int i = 1; i <= n; i++) { if(p[a[i]]) Add_Edge(src, i, 1); else Add_Edge(i, sink, 1); } for(int i = 1; i <= n; i++) { if(p[a[i]]) { for(int j = 1; j <= n; j++) { if(!p[a[j]]) { if(a[i] > a[j]) { if(a[i] % a[j] == 0 && prime[a[i] / a[j]]) Add_Edge(i, j, 1); } else { if(a[j] % a[i] == 0 && prime[a[j] / a[i]]) Add_Edge(i, j, 1); } } } } } printf("%d\n", n - ISAP(src, sink)); } }
时间: 2024-10-12 07:50:53