(二分+二分匹配)
题意:总共
思路:将模型转化为二分图的最大匹配来做,二分图左边为前
代码:
#include <cstdio>
#include <set>
#include <vector>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
const int maxn = 3010;
const int maxm = 1000010;
int a[maxn];
vector<int> pri[maxn];
int head[maxn], cnt;
struct e{
int to, next;
}edge[maxn<<3];
void init_graph(int n) { cnt = 0; memset(head, -1, sizeof(head[0])*(n+5)); }
void add_edge(int u, int v){
edge[cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt ++;
}
bool bmask[maxm];
int cx[maxn], cy[maxm];
int findpath(int u){
for(int k=head[u]; k!=-1; k=edge[k].next){
int i = edge[k].to;
if(!bmask[i]){
bmask[i] = 1;
if(cy[i] == -1 || findpath(cy[i])){
cy[i] = u;
cx[u] = i;
return 1;
}
}
}
return 0;
}
int MaxMatch(int nx, int ny){
int ret = 0;
memset(cx,-1,sizeof(cx[0])*(nx+5));
memset(cy,-1,sizeof(cy[0])*(ny+5));
for(int i=1; i<=nx; i++)
if(cx[i] == -1){
memset(bmask,0,sizeof(bmask[0])*(ny+5));
ret += findpath(i);
}
return ret;
}
set<int> S;
set<int>::iterator iter;
vector<int> vec_y;
bool work(int n) {
init_graph(n);
S.clear();
for(int i=1; i<=n; i++) {
int sz = pri[i].size();
for(int j=0; j<sz; j++)
S.insert(pri[i][j]);
}
vec_y.clear();
for(iter=S.begin(); iter!=S.end(); iter++)
vec_y.push_back(*iter);
for(int i=1; i<=n; i++) {
int sz = pri[i].size();
for(int j=0; j<sz; j++) {
int k = lower_bound(vec_y.begin(), vec_y.end(), pri[i][j]) - vec_y.begin() + 1;
add_edge(i, k);
}
}
if(MaxMatch(n, (int)vec_y.size()) == n) return true;
return false;
}
int main() {
int n;
while(scanf("%d",&n) == 1) {
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
pri[i].clear(); int t = a[i];
for(int j=2; j*j<=t; j++) if(t%j == 0) {
pri[i].push_back(j);
while(t%j == 0) t /= j;
}
if(t > 1) pri[i].push_back(t);
}
int l = 1, r = n;
while(l < r) {
int mid = (l+r+1)/2;
if(work(mid)) l = mid;
else r = mid - 1;
}
printf("%d\n",l);
}
return 0;
}