Untitled ( DFS 递归 )

There is an integer a and n integers b1,…,bn. After selecting some numbers from b1,…,bn in any order, say c1,…,cr, we want to make sure that a mod c1 mod c2 mod… mod cr=0 (i.e., a will become the remainder divided by cici each time, and at the end, we want a to become 0). Please determine the minimum value of r. If the goal cannot be achieved, print −1 instead.
Input
The first line contains one integerT≤5, which represents the number of testcases.

For each testcase, there are two lines:

1. The first line contains two integers nn and aa (1≤n≤20,1≤a≤106).

2. The second line contains nn integers b1,…,bnb1,…,bn (∀1≤i≤n,1≤bi≤106).
Output
Print TT answers in TT lines.
Sample Input
2
2 9
2 7
2 9
6 7
Sample Output
2

-1


题意:给一个数a和n个数,要你从这n个数中找到最少r个数使得a%完r个数后等于零

思路:先将数组从大到小排序(为什么呢?因为后面模完一个数后就变得很小,只要记录前一个模完的数的位置,下一次dfs从那个位置往后扫就行了,若是乱序还得一个一个扫,若是升序从末尾往前扫也是一样的,若从小到大扫若遇到比模完之后还大的数还要从头扫)然后进入DFS,得到一个使m等于零的解就保存数的个数,然后继续找,若a数组扫到末尾都比m大,则说明找不到了,没有解。


AC代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<cstdlib>
using namespace std;
int n,m,ans;
int a[25];
bool dfs(int m,int cnt,int deep){
    if(m==0){                 //若找到了第deep个数,即m膜完deep个数后等于零,说明这是一个可能的最优解了
        ans=min(ans,deep);  //接下来这个解与前面得到的解作比较,因为题目要求的是输出找到的最少的个数
        return true;          //bool类型为true 这时肯定是存在一个deep使m==0的
    }
    int i;
    for(i=cnt;i<n;i++){     //首先要做的工作就是找到小于等于m的数,因为大于m的数没有用,模完还是等于本身,开始i
                             //等于cnt是因为不用重复扫,因为m模完前一个数肯定比那些数小
        if(a[i]<=m)
            break;
    }
    if(i==n)return false;  //如果扫完整个数组a都是大于m的说明不可能存在一个数x使m%x等于0了
    for( ;i<n;i++)         //从刚好小于等于m的数开始对m取模
        return dfs(m%a[i],cnt+1,deep+1);
}
bool cmp(int a,int b){
    return a>b;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        ans=10000;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        sort(a,a+n,cmp);          //先将数组从大到小排序
        if(!dfs(m,0,0))printf("-1\n");
        else printf("%d\n",ans);
    }
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值