【深度优先搜索习题】 分成互质组

目录

1. 题目描述

2. 思路解释

3. 代码实现(局部代码)

1. 变量定义

2. 主函数:输入+dfs+输出

3. dfs函数

4. check函数(检查是否互质)

5. gcd函数(求最大公约数)

4. 完整代码:


1. 题目描述

OpenJudge - 7834:分成互质组

2. 思路解释

每次选择一个数进入所分好的组,比较这个数与分组中每个数是否互质,互质则进入此分组,否则新开辟一个分组

3. 代码实现(局部代码)

1. 变量定义

  • n n个数
  • p[20]  存数
  • group[20][20]  最多可能有N个组, 每个组可能有N个数 存的是数的序号(保证可以连续性访问)
  • st[20]  标记每个数是否用过
  • res=20  组数的最大值是n个数两两互质

2. 主函数:输入+dfs+输出

int main ()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>p[i];
    dfs(1,0,0,0);
    cout<<res<<endl;
    return 0;
}

3. dfs函数

u -> 第几组
v -> 第几组中的第几个数
w -> 我用了多少个数
x -> 当前从哪个序列编号开始找下一个互质的数放入组中

void dfs(int u,int v,int w,int x)  // 递归指数型枚举
{
    if(u>=res) return ;
    if(w==n) 
    {
        res=u;
        return ; 
    }
    bool flag=1;  
    for(int i=x;i<n;i++)
        if(!st[i] && check(u,v,i))
        {
            group[u][v]=i;
            st[i]=1;
            flag=0;
	    	dfs(u,v+1,w+1,i+1);
            st[i]=0;
        }
        if(flag) dfs(u+1,0,w,0); 
}

我们此时的flag变量即标记是否互质变量,初始值赋值为1,如果被选了则被赋值为0,没被选则还是1,此时我们就要新开辟一个分组,因为这个数与其他分组中的数不互质,不符合题目要求。

4. check函数(检查是否互质)

bool check(int u,int v,int i)
{
    for(int j=0;j<v;j++)
    {
    	if(gcd(p[group[u][j]],p[i])>1) return 0;
	} 
    return 1;
}

采用gcd函数判断分组内的每一个数是否与新加进来的数互质,互质返回1,否则返回0

5. gcd函数(求最大公约数)

int gcd (int a, int b)
{
    return b?gcd(b,a%b):a;
}

判断这两个数的最大最大公约数,众所周知,当两个数互质时,最大公约数为1,否则肯定大于1,我们返回这两个数的最大公约数,在check函数中判断最大公约数是否大于1来判断是否互质

这一段代码为简写,此函数的正常写法和证明在下面这个链接中,大家自行阅览

【模板代码】辗转相除法gcd(图像证明法)-CSDN博客

4. 完整代码:

#include<bits/stdc++.h>
using namespace std;
int n;
int p[20];
int group[20][20]; 
bool st[20];
int res = 20;
int gcd (int a, int b)
{
    return b?gcd(b,a%b):a;
}
bool check(int u,int v,int i)
{
    for(int j=0;j<v;j++)
    {
    	if(gcd(p[group[u][j]],p[i])>1) return 0;
	} 
    return 1;
}
void dfs(int u,int v,int w,int x)  
{
    if(u>=res) return ;
    if(w==n) 
    {
        res=u;
        return ;  
    }
    bool flag=1;  
    for(int i=x;i<n;i++ )
        if(!st[i] && check(u,v,i))
        {
            group[u][v]=i;
            st[i]=1;
            flag=0;
	    	dfs(u,v+1,w+1,i+1);
            st[i]=0;
        }
        if(flag) dfs(u+1,0,w,0); 
}
int main ()
{
    cin>>n;
    for(int i=0;i<n;i++) cin>>p[i];
    dfs(1,0,0,0);
    cout<<res<<endl;
    return 0;
}

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值