题意:有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. GridView解决同一行item的高度不一样,如何同一行统一高度问题?

    问题描述: 有时我们使用GridView会面对类似这种情况. 这是是不是一脸愣逼,我们理想情况是把他变成这样 保证同一行的item都是一样高这样就美观许多了 注意:上面的两张图片是盗图,用来作为效果观 ...

  2. deep learning+ Depth Estimation

    Depth estimation/stereo matching/optical flow @CVPR 2017 Unsupervised Learning of Depth and Ego-Moti ...

  3. crontab读不来环境变量

    无法识别java nohup: failed to run command `java': No such file or directory 那么在shell中加两行即可解决 . /etc/prof ...

  4. poj 3498(最大流+拆点)

    题目链接:http://poj.org/problem?id=3498 思路:首先设一个超级源点,将源点与各地相连,边容量为各点目前的企鹅数量,然后就是对每个冰块i进行拆点了(i,i+n),边容量为能 ...

  5. 如何正确使用Google搜索

    “” 双引号表示完全匹配,结果中必须出现与搜索文本完全相同的内容 A -B 搜索包含A但不包含B的结果(请注意A后面的空格不能省略) filetype 搜索对应类型的文件.例如:中国防火墙 filet ...

  6. ddos cc攻击简单介绍(转)

    何为syn flood攻击: SYN Flood是一种广为人知的DoS(拒绝服务攻击)是DDoS(分布式拒绝服务攻击)的方式之一,这是一种利用TCP协议缺陷,发送大量伪造的TCP连接请求,从而使得被攻 ...

  7. bat脚本中timeStamp解决方案

    之前做了个工具包,用了timeStamp做文件名. 一般来说最简单的代码类似于: set timeStamp=%date:/=-%_%time% echo %timeStamp% >2018-0 ...

  8. 【BZOJ4379】[POI2015]Modernizacja autostrady 树形DP

    [BZOJ4379][POI2015]Modernizacja autostrady Description 给定一棵无根树,边权都是1,请去掉一条边并加上一条新边,定义直径为最远的两个点的距离,请输 ...

  9. 存一些可能会用得到的vue的UI框架

    VUX 项目主页:https://vux.li/#/ github地址:https://github.com/airyland/vux element UI(饿了么后台) Element 是由饿了么U ...

  10. Understanding Tensorflow using Go

    原文: https://pgaleone.eu/tensorflow/go/2017/05/29/understanding-tensorflow-using-go/ Tensorflow is no ...