题意:有N个数的集合,其中选出若干个数组成一个子集,要求这个子集中的任意两个数a,b都不能通过a=k*b得到,其中k是一个素数。求这个子集最大的size。

分析:集合中任意两数的关系是二者之间是否之差一个质因子,那么对于这种关系,本题要求的是N个点的最大独立集。|最大独立集| = 点数 - |二分图最大匹配|。

想到这步之后,就是如何建图的问题。

先预处理筛出一定范围内的素数。对于每个集合内的数a,检查其除去一个质因子后得到的数at是否在集合中出现,若出现则将a到at和at到a建边。

因为是双向建边,所以得到的最大匹配数是两倍,除以2即可。

    #include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = ;
const int MAXM = *;
const int INF = 0x3f3f3f3f;
int N;
struct Node{
int x,y;
}p[MAXN],it[MAXN];
int v[MAXN]; struct Edge{
int v;
int next;
}edge[MAXM]; int nx, ny;
int cnt;
int t;
int dis; int first[MAXN];
int xlink[MAXN], ylink[MAXN];
/*xlink[i]表示左集合顶点所匹配的右集合顶点序号,ylink[i]表示右集合i顶点匹配到的左集合顶点序号。*/
int dx[MAXN], dy[MAXN];
/*dx[i]表示左集合i顶点的距离编号,dy[i]表示右集合i顶点的距离编号*/
int vis[MAXN]; //寻找增广路的标记数组
void init(){
cnt = ;
memset(first, -, sizeof(first));
memset(xlink, -, sizeof(xlink));
memset(ylink, -, sizeof(ylink));
} void AddEdge(int u, int v){
edge[cnt].v = v;
edge[cnt].next = first[u], first[u] = cnt++;
} int bfs()
{
queue<int> q;
dis = INF;
memset(dx, -, sizeof(dx));
memset(dy, -, sizeof(dy));
for(int i = ; i <= nx; i++){
if(xlink[i] == -){
q.push(i);
dx[i] = ;
}
}
while(!q.empty()){
int u = q.front(); q.pop();
if(dx[u] > dis) break;
for(int e = first[u]; e != -; e = edge[e].next){
int v = edge[e].v;
if(dy[v] == -){
dy[v] = dx[u] + ;
if(ylink[v] == -) dis = dy[v];
else{
dx[ylink[v]] = dy[v]+;
q.push(ylink[v]);
}
}
}
}
return dis != INF;
} int find(int u){
for(int e = first[u]; e != -; e = edge[e].next){
int v = edge[e].v;
if(!vis[v] && dy[v] == dx[u]+){
vis[v] = ;
if(ylink[v] != - && dy[v] == dis) continue;
if(ylink[v] == - || find(ylink[v])){
xlink[u] = v, ylink[v] = u;
return ;
}
}
}
return ;
} int MaxMatch()
{
int ans = ;
while(bfs()){
memset(vis, , sizeof(vis));
for(int i = ; i <= nx; i++)
if(xlink[i] == -)
ans += find(i);
}
return ans;
} const int MAXV = ;
int prime[MAXV];
bool notprime[MAXV*];
void pre()
{
int up = MAXV *;
memset(notprime,,sizeof(notprime));
notprime[] = notprime[] = true;
memset(prime,,sizeof(prime));
for(int i=;i<up;++i){
if(!notprime[i]) prime[++prime[]] = i;
for(int j= ; j<=prime[] && prime[j] <= up / i ;++j){
notprime[prime[j]*i] = true;
if(i%prime[j]==) break;
}
}
} int pos[MAXV*];
int num[MAXV];
int fac[MAXV];
bool jo[MAXV*];
void ADD(int num,int pt){
int sum = ,all=;
int tmp = num;
for(int i=;prime[i]*prime[i]<=tmp;i++){
if(tmp%prime[i]==){
fac[sum++] = prime[i];
while(tmp%prime[i]==) tmp/=prime[i],all++;
}
}
if(tmp>) fac[sum++] = tmp,all++;
for(int i=;i<sum;++i){
int x = num/fac[i];
if(pos[x]){
AddEdge(pt,pos[x]);
AddEdge(pos[x],pt);
}
}
} int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
pre();
int T,cas=; scanf("%d",&T);
while(T--){
int N; scanf("%d",&N);
init();
memset(pos,,sizeof(pos));
for(int i=;i<=N;++i){
scanf("%d",&num[i]);
pos[num[i]] = i;
}
nx = ny =;
for(int i=;i<=N;++i){
ADD(num[i],i);
}
nx = ny = N;
int res= N - MaxMatch()/;
printf("Case %d: %d\n",cas++,res);
}
return ;
}

LightOJ - 1356 Prime Independence (数论+二分图匹配)的更多相关文章

  1. LightOJ 1356 Prime Independence 二分图最大独立集,HK算法

    这个题唯一需要说的就是普通的匈牙利算法是O(nm)的,过不了 然后HK算法可以O(n^0.5m),这个算法可以每次找很多同样长度的最短增广路 分析见:http://www.hardbird.net/l ...

  2. LightOJ - 1356 Prime Independence (二分图 最大独立集 素数打表)

    题意: 给你一个集合,让你从这个集合中挑选出几个数,使得这几个数中任意两个数相除后的值不能为素数 即挑选出来的这几个数不能互相冲突 最大独立集 = 所有点数 - 最大匹配数 呵..呵...原先用的二维 ...

  3. LightOJ 1356 Prime Independence(质因数分解+最大独立集+Hopcroft-Carp)

    http://lightoj.com/login_main.php?url=volume_showproblem.php?problem=1356 题意: 给出n个数,问最多能选几个数,使得该集合中的 ...

  4. HDU 5938 Kingdom of Obsession(数论 + 二分图匹配)

    题意: 给定S,N,把S+1,S+2,...S+N这N个数填到1,2,...,N里,要求X只能填到X的因子的位置.(即X%Y=0,那么X才能放在Y位置) 问是否能够放满. 分析:经过小队的分析得出的结 ...

  5. 【ARC080F】Prime Flip 差分+二分图匹配

    Description ​ 有无穷个硬币,初始有n个正面向上,其余均正面向下.  你每次可以选择一个奇质数p,并将连续p个硬币都翻转.  问最小操作次数使得所有硬币均正面向下. Input ​ 第一行 ...

  6. csu 1552(米勒拉宾素数测试+二分图匹配)

    1552: Friends Time Limit: 3 Sec  Memory Limit: 256 MBSubmit: 723  Solved: 198[Submit][Status][Web Bo ...

  7. zoj3988 二分图匹配

    给一个数组,对于每两个数加起来为素数那么就是一个集合,求不超过k个集合的最多数是多少 解法:二分图匹配,先打素数筛,预处理边集,匹配完之后分两种情况k>匹配数,那么可以直接输出匹配数*2,否则可 ...

  8. Help Hanzo (LightOJ - 1197) 【简单数论】【筛区间质数】

    Help Hanzo (LightOJ - 1197) [简单数论][筛区间质数] 标签: 入门讲座题解 数论 题目描述 Amakusa, the evil spiritual leader has ...

  9. CodeFroces New Assignment 二分图匹配

    There is a class consisting of n students, in which each one has a number representing his/her perso ...

随机推荐

  1. pl/sql 实例精解 05

    本章主要讨论 case 语句 1: case [SELECTOR] 2: when expression 1 then statement 1; 3: when expression 2 then s ...

  2. Asp.Net中使用水晶报表

    Asp.Net中使用水晶报表(上) 在我们对VS.Net中的水晶报表(Crystal Reports)进行研究之前,我和我朋友对如何将这个复杂的东东加入我们的Web应用有着非常的好奇心.一周以后,在阅 ...

  3. Android将指定的.class打包到mainDex中

    1️⃣ 我们分包的时候会遇到一个问题,因为加载和初始化的问题,如果某个类不在mainDex中,那么程序就会报错,java.lang.NoClassDefFoundError. 2️⃣ 在gradle中 ...

  4. 【BZOJ】1827: [Usaco2010 Mar]gather 奶牛大集会(树形dp)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1827 仔细想想就好了,, 每个点维护两个值,一个是子树的费用,一个是除了子树和自己的费用.都可以用d ...

  5. (转)Java锁、自旋锁、CAS机制

    转自:http://www.jb51.net/article/55381.htm 转自:http://blog.csdn.net/aesop_wubo/article/details/7537278 ...

  6. 【python】获取网页中中文内容并分词

    # -*- coding: utf-8 -*- import urllib2 import re import time import jieba url="http://www.baidu ...

  7. Chrome 新建自定义标签

    刚开始用Chrome让我最不爽的地方有2个: 1.不能双击关闭标签 2.新建的标签不能是自定义网页 第一个问题通过插件解决了,第二个问题今天也总算找到解决的方法了. 这个方法是自定义插件,需要2个文件 ...

  8. (转)QT中QWidget、QDialog及QMainWindow的区别

    QWidget类是所有用户界面对象的基类. 窗口部件是用户界面的一个基本单元:它从窗口系统接收鼠标.键盘和其它事件,并且在屏幕上绘制自己.每一个窗口部件都是矩形的,并且它们按Z轴顺序排列.一个窗口部件 ...

  9. 网络虚拟化之FlowVisor:网络虚拟层(下)

    在前面两篇文章:网络虚拟化之FlowVisor:网络虚拟层(上)和网络虚拟化之FlowVisor:网络虚拟层(中)中分别介绍了FLowVisor的特性和实现,三连载的最后一篇介绍虚拟网络的隔离机制. ...

  10. 【BZOJ4260】Codechef REBXOR Trie树+贪心

    [BZOJ4260]Codechef REBXOR Description Input 输入数据的第一行包含一个整数N,表示数组中的元素个数. 第二行包含N个整数A1,A2,…,AN. Output ...