题意:从N个数中找出一个最大子集,满足这个集合中的任意两个数都不存在质数倍的关系,就匹配1和3就是质数(3)倍,然而1和4就不是质数倍。
分析:很明显的,从联通集合中求出一个最大独立集,就是独立集问题了,再一分析,不存在“x乘以(质数乘以质数)=y”这样的情况,所以可以看出,这是一个二分图。那么问题变成了求二分图的最大独立集这样的一个问题了。于是,再一分析,我们可以发现这a[i]各不相同,所以我们直接进行存位置,然后链接边,就可以了,这里用HK来跑,用匈牙利的话,是会TLE的。
当然,这里犯了个大错,就是当求质数的时候,我们可以用x的质数倍存在与否而不是x的质因子除去后的数存在与否,会比较的方便。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <string> 5 #include <cstring> 6 #include <algorithm> 7 #include <limits> 8 #include <vector> 9 #include <stack> 10 #include <queue> 11 #include <set> 12 #include <map> 13 #include <bitset> 14 #include <unordered_map> 15 #include <unordered_set> 16 #define lowbit(x) ( x&(-x) ) 17 #define pi 3.141592653589793 18 #define e 2.718281828459045 19 #define INF 0x3f3f3f3f 20 #define HalF (l + r)>>1 21 #define lsn rt<<1 22 #define rsn rt<<1|1 23 #define Lson lsn, l, mid 24 #define Rson rsn, mid+1, r 25 #define QL Lson, ql, qr 26 #define QR Rson, ql, qr 27 #define myself rt, l, r 28 #define pii pair<int, int> 29 #define MP(a, b) make_pair(a, b) 30 using namespace std; 31 typedef unsigned long long ull; 32 typedef unsigned int uit; 33 typedef long long ll; 34 const int maxN = 4e4 + 7; 35 vector<int> Prime; 36 bool vis[500005] = {false}; 37 void Prime_Init() 38 { 39 for(int i = 2; i <= 500000; i ++) 40 { 41 if(!vis[i]) 42 { 43 Prime.push_back(i); 44 for(int j = i * 2; j <= 500000; j += i) vis[j] = true; 45 } 46 } 47 } 48 int N, a[maxN], pos[500005]; 49 int head[maxN], cnt; 50 struct Eddge 51 { 52 int nex, to; 53 Eddge(int a=-1, int b=0):nex(a), to(b) {} 54 } edge[1000006]; 55 inline void addEddge(int u, int v) 56 { 57 edge[cnt] = Eddge(head[u], v); 58 head[u] = cnt ++; 59 } 60 inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); } 61 void init() 62 { 63 cnt = 0; 64 for(int i = 1; i <= N; i ++) head[i] = -1; 65 } 66 namespace HK 67 { 68 int mx[maxN], my[maxN]; 69 int dx[maxN], dy[maxN], dis; 70 bool vis[maxN]; 71 bool searchP() 72 { 73 queue<int> Q; 74 dis = INF; 75 for(int i = 1; i <= N; i ++) dx[i] = -1; 76 for(int i = 1; i <= N; i ++) dy[i] = -1; 77 for(int i = 1; i <= N; i ++) 78 { 79 if(mx[i] == -1) 80 { 81 Q.push(i); 82 dx[i] = 0; 83 } 84 } 85 while(!Q.empty()) 86 { 87 int u = Q.front(); Q.pop(); 88 if(dx[u] > dis) break; 89 for(int i = head[u], v; ~i; i = edge[i].nex) 90 { 91 v = edge[i].to; 92 if(dy[v] == -1) 93 { 94 dy[v] = dx[u] + 1; 95 if(my[v] == -1) dis = dy[v]; 96 else 97 { 98 dx[my[v]] = dy[v] + 1; 99 Q.push(my[v]); 100 } 101 } 102 } 103 } 104 return dis != INF; 105 } 106 bool dfs(int u) 107 { 108 for(int i = head[u], v; ~i; i = edge[i].nex) 109 { 110 v = edge[i].to; 111 if(!vis[v] && dy[v] == dx[u] + 1) 112 { 113 vis[v] = 1; 114 if(my[v] != -1 && dy[v] == dis) continue; 115 if(my[v] == -1 || dfs(my[v])) 116 { 117 my[v] = u; 118 mx[u] = v; 119 return 1; 120 } 121 } 122 } 123 return 0; 124 } 125 int MaxMatch() 126 { 127 int res = 0; 128 for(int i = 1; i <= N; i ++) mx[i] = -1; 129 for(int i = 1; i <= N; i ++) my[i] = -1; 130 while(searchP()) 131 { 132 for(int i = 1; i <= N; i ++) vis[i] = false; 133 for(int i = 1; i <= N; i ++) 134 { 135 if(mx[i] == -1 && dfs(i)) res ++; 136 } 137 } 138 return res; 139 } 140 } 141 using namespace HK; 142 int main() 143 { 144 Prime_Init(); 145 int T; scanf("%d", &T); 146 for(int Cas = 1; Cas <= T; Cas ++) 147 { 148 scanf("%d", &N); 149 int maxx = 1; 150 for(int i = 1; i <= N; i ++) { scanf("%d", &a[i]); maxx = max(maxx, a[i]); } 151 for(int i = 1; i <= N; i ++) pos[a[i]] = i; 152 init(); int len = (int)Prime.size(); 153 for(int i = 1, x; i <= N; i ++) 154 { 155 x = a[i]; 156 for(int j = 0, v; j < len && Prime[j] * a[i] <= maxx; j ++) 157 { 158 v = pos[Prime[j] * a[i]]; 159 if(!v) continue; 160 _add(i, v); 161 } 162 } 163 printf("Case %d: %d\n", Cas, N - MaxMatch() / 2); 164 for(int i = 1; i <= N; i ++) pos[a[i]] = 0; 165 } 166 return 0; 167 }