Lightoj1356
题目链接:https://vjudge.net/problem/LightOJ-1356
题目大意:
T个 test case,每个 test case 给出一个 N 个数的集合。请找出一个最大的子集,使得子集中的任何一个数除以子集中的任意的另一个数所得到的数不是质数。
解题思路:
先用素数筛找出 1 到 500000 的所有质数。
在输入一个集合的时候,我们顺便记录下输入的这个数在输入数组中的位置,找出它的所有质因数,记录下质因数的总个数,用一个vector记录下所有 “不同的” 质因数。
遍历输入数组中的每一个数,对于每个数,遍历其所有 “不同的” 质因数,如果找到这样的一个质因数:该数除以这个质因数能得到输入数组中的另一个数,那么将这两个数连边。
将由上述的连边操作得到的图中的点分成两类:质因数总个数为奇数的点和质因数总个数为偶数的点(这个划分有点隐晦,我多说两句:其实,对于连边的两个数,二者各自的所有质因数其实就只有一个质数的差别,其中一个数的所有质因数中有这个质数,但另一个数没有,其他的质因数都相同;所以,他们质因数的总个数相差 1,故其中一个为奇数,一个为偶数),这样一来,这个图就变成一个二分图了。而答案其实就是求这个二分图的最大独立集。
另:用匈牙利算法者,T!用 Hopcroft-Carp者方有可能AC。
AC代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue> using namespace std;
const int inf=0x3f3f3f3f; bool prime[];
int have[],num[];
int prims[]; vector<int> G[];
int uN;
int l[];
int Mx[],My[];
int dx[],dy[];
int dis;
bool used[];
bool SearchP(){
queue<int>Q;
dis=inf;
memset(dx,-,sizeof(dx));
memset(dy,-,sizeof(dy));
for(int i=;i<uN;i++){
if(Mx[l[i]]==-){
Q.push(l[i]);
dx[l[i]]=;
}
}
while(!Q.empty()){
int u=Q.front();
Q.pop();
if(dx[u]>dis) break;
int sz=G[u].size();
for(int i=;i<sz;i++){
int v=G[u][i];
if(dy[v]==-){
dy[v]=dx[u]+;
if(My[v]==-) dis=dy[v];
else{
dx[My[v]]=dy[v]+;
Q.push(My[v]);
}
}
}
}
return dis!=inf;
}
bool DFS(int u){
int sz=G[u].size();
for(int i=;i<sz;i++){
int v=G[u][i];
if(!used[v]&&dy[v]==dx[u]+){
used[v]=true;
if(My[v]!=-&&dy[v]==dis) continue;
if(My[v]==-||DFS(My[v])){
My[v]=u;
Mx[u]=v;
return true;
}
}
}
return false;
}
int MaxMatch(){
int res=;
memset(Mx,-,sizeof(Mx));
memset(My,-,sizeof(My));
while(SearchP()){
memset(used,false,sizeof(used));
for(int i=;i<uN;i++){
if(Mx[l[i]]==-&&DFS(l[i])) res++;
}
}
return res;
}
void init(){
memset(prime,true,sizeof(prime));
prime[]=prime[]=false;
int cnt=;
for(int i=;i<=;i++){
if(prime[i]){
prims[cnt++]=i;
for(int j=*i;j<=;j+=i)
prime[j]=false;
}
}
}
int zhis[];
vector<int> zhiyinshu[];
int main(){
init();
int T,N;
scanf("%d",&T);
for(int t=;t<=T;t++){
scanf("%d",&N);
memset(have,,sizeof(have));
memset(zhis,,sizeof(zhis));
for(int i=;i<=N;i++){
G[i].clear();
zhiyinshu[i].clear();
scanf("%d",&num[i]);
have[num[i]]=i;
int tmp=num[i];
for(int j=;;j++){
if(prime[tmp]){
zhiyinshu[i].push_back(tmp);
zhis[i]++;
break;
}
if(tmp%prims[j]==){
tmp/=prims[j];
zhiyinshu[i].push_back(prims[j]);
zhis[i]++;
while(tmp%prims[j]==){
tmp/=prims[j];
zhis[i]++;
}
}
if(tmp<prims[j]) break;
}
}
for(int i=;i<=N;i++){
for(int j=;j<zhiyinshu[i].size();j++){
if(have[num[i]/zhiyinshu[i][j]]){
int u=have[num[i]/zhiyinshu[i][j]];
G[i].push_back(u);
G[u].push_back(i);
}
}
} uN=;
for(int i=;i<=N;i++){
if(zhis[i]%==){
l[uN++]=i;
}
}
printf("Case %d: %d\n",t,N-MaxMatch());
}
return ;
}
Lightoj1356的更多相关文章
- Lightoj-1356 Prime Independence(质因子分解)(Hopcroft-Karp优化的最大匹配)
题意: 找出一个集合中的最大独立集,任意两数字之间不能是素数倍数的关系. 思路: 最大独立集,必然是二分图. 最大数字50w,考虑对每个数质因子分解,然后枚举所有除去一个质因子后的数是否存在,存在则建 ...
随机推荐
- ajax 技术
ajax 技术 $.ajax({ url:"", type:'GET', success:function(data){ console.log(data); }, error:f ...
- Redis数据迁移的三个方法
为什么80%的码农都做不了架构师?>>> 1. rdb数据备份恢复方法 redis 127.0.0.1:6379> SAVE OK 或者 redis-cli -h 127. ...
- mysql硬件优化
导致宕机的原因: 1. 运行环境: 35%,运行环境可以看做是支持数据库服务器运行的系统和资源集合,包括操作系统,硬盘以及网络 2. 性能:35% 3. 复制 20% 4 ...
- MySQL重新初始化安装数据库
删除./mysql/var下的所有数据后,怎么重新安装初始数据库? (1)进入./mysql/bin目录下,执行脚本./mysql_install_db: (2)执行完(1)后,此时会在./mysq ...
- P1466 集合 Subset Sums 搜索+递推+背包三种做法
题目描述 对于从1到N (1 <= N <= 39) 的连续整数集合,能划分成两个子集合,且保证每个集合的数字和是相等的.举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,每个子 ...
- 无向图求割(找桥)tarjan
本博客参考了李煜东的<算法竞赛进阶指南>,大家要是觉得这篇文章写的不错请大家支持正版.豆瓣图书 我在之前的博客中讲解了搜索序时间戳,这次我们讲讲追溯值的概念. 追溯值: 设subtree( ...
- rabbitmq添加自启动 centos7环境
1.编辑一个启动脚本 [root@xxx ~]# vim /usr/local/rabbitmq/sbin/start_rabbitmq.sh 内容如下(根据自己的实际位置做替换即可) #!/bin/ ...
- 「译」JVM是如何使用那些你从未听过的x86魔幻指令实现String.compareTo的
原文https://jcdav.is/2016/09/01/How-the-JVM-compares-your-strings/ 魔幻的String.compareTo 我们之前可能已经见过Java的 ...
- Java λ表达式
目录 Java Lambda表达式 1. 函数式编程思想 2. 体验Lambda的更优写法 3. Lambda表达式的标准格式 4. 练习:使用Lambda表达式(无参无返回) 5. 练习:使用Lam ...
- http协议跟tcp协议的简单理解
在说明这两个协议之前,我们先简单说一下网络的分层. 1)应用层 支持网络应用,应用协议仅仅是网络应用的一个组成部分,运行在不同主机上的进程则使用应用层协议进行通信.主要的协议有:http.ftp.te ...