LightOJ - 1356 Prime Independence (数论+二分图匹配)
题意:有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 (数论+二分图匹配)的更多相关文章
- LightOJ 1356 Prime Independence 二分图最大独立集,HK算法
这个题唯一需要说的就是普通的匈牙利算法是O(nm)的,过不了 然后HK算法可以O(n^0.5m),这个算法可以每次找很多同样长度的最短增广路 分析见:http://www.hardbird.net/l ...
- LightOJ - 1356 Prime Independence (二分图 最大独立集 素数打表)
题意: 给你一个集合,让你从这个集合中挑选出几个数,使得这几个数中任意两个数相除后的值不能为素数 即挑选出来的这几个数不能互相冲突 最大独立集 = 所有点数 - 最大匹配数 呵..呵...原先用的二维 ...
- LightOJ 1356 Prime Independence(质因数分解+最大独立集+Hopcroft-Carp)
http://lightoj.com/login_main.php?url=volume_showproblem.php?problem=1356 题意: 给出n个数,问最多能选几个数,使得该集合中的 ...
- HDU 5938 Kingdom of Obsession(数论 + 二分图匹配)
题意: 给定S,N,把S+1,S+2,...S+N这N个数填到1,2,...,N里,要求X只能填到X的因子的位置.(即X%Y=0,那么X才能放在Y位置) 问是否能够放满. 分析:经过小队的分析得出的结 ...
- 【ARC080F】Prime Flip 差分+二分图匹配
Description 有无穷个硬币,初始有n个正面向上,其余均正面向下. 你每次可以选择一个奇质数p,并将连续p个硬币都翻转. 问最小操作次数使得所有硬币均正面向下. Input 第一行 ...
- csu 1552(米勒拉宾素数测试+二分图匹配)
1552: Friends Time Limit: 3 Sec Memory Limit: 256 MBSubmit: 723 Solved: 198[Submit][Status][Web Bo ...
- zoj3988 二分图匹配
给一个数组,对于每两个数加起来为素数那么就是一个集合,求不超过k个集合的最多数是多少 解法:二分图匹配,先打素数筛,预处理边集,匹配完之后分两种情况k>匹配数,那么可以直接输出匹配数*2,否则可 ...
- Help Hanzo (LightOJ - 1197) 【简单数论】【筛区间质数】
Help Hanzo (LightOJ - 1197) [简单数论][筛区间质数] 标签: 入门讲座题解 数论 题目描述 Amakusa, the evil spiritual leader has ...
- CodeFroces New Assignment 二分图匹配
There is a class consisting of n students, in which each one has a number representing his/her perso ...
随机推荐
- 参考 generate-parentheses
分析: 关键:当前位置左括号不少于右括号 图是什么? 节点:目前位置左括号和右括号数(x,y)(x>=y) 边:从(x,y)到(x+1,y)和(x,y+1) ...
- C++ 类的多态五(多态的语法本质分析)
//多态的语法本质分析 #include<iostream> using namespace std; /* 三种易混淆的多态场景 */ class Point{ public: Poin ...
- NIPS(Conference and Workshop on Neural Information Processing Systems)
论文提交时间:5月下旬 会议时间:12月上旬 NIPS2017: 网址:https://nips.cc/
- Ubuntu apt-get update错误解决
用apt-get命令安装开发软件非常方便,但由于各种原因,经常链接不上软件源,于是需要使用sudo apt-get update命令来更新软件源. 而屋漏偏逢连夜雨,这时候更新命令也罢工,出现各种错误 ...
- Java WEB应用开发
B/S计算模式的3层架构: 软件设计与开发模式的演化 面向机器语言的开发模式 软件的生命周期开发模式 需求分析 系统设计 系统开发 系统测试 运行和维护 原型法开发模式 面向组件(Component) ...
- 用MathType编辑上下尖括号有什么技巧
在MathType中,同一个数学符号可以进行各种变换方向的使用,就比如箭头符号,任意方向都可以使用,这也是很常见的.数学中的符号能够根据各种特殊需要进行灵活使用,除了箭头符号之外,其它符号也可以,比如 ...
- Visual Studio 2015 自定义文件编译
自己编译好了 QT 5.6.0 Alpha 版本后,如何使用 VS2015 创建 QT 工程呢? 1.安装插件,安装失败!因为 VS2015 不再支持 ADDIN , 所以 QT-VS-ADDIN 只 ...
- Vue与React的异同 -生命周期
vue的生命周期 创建前 beforeCreate 创建 create 挂载前 beforeMount 挂载 mounted 更新前 beforeUpdate 更新 updated 销毁前 bef ...
- PAT 甲级 1003Emergency(Dijkstra最短路)
1003. Emergency (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue As an emerg ...
- Python IDLE或shell中切换路径
在Python自带的编辑器IDLE中或者python shell中不能使用cd命令,那么跳到目标路径呢.方法是使用os包下的相关函数实现路径切换功能. import os os.getcwd() # ...