zoukankan      html  css  js  c++  java
  • 【搜索练习】【一】

     

    n的全排列

    题目描述

    输入一个整数n,输出的n的全排列。

    输入

     

    输出

     

    样例输入

    3
    

    样例输出

    1 2 3
    1 3 2
    2 1 3
    2 3 1
    3 1 2
    3 2 1

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    
    using namespace std;
    int n;
    int visi[1005],a[1005];
    void print(int x) 
    { 
        for(int i=1;i<x;++i)printf("%d ",a[i]); 
        printf("%d",a[x]); 
        puts("");
    } 
    void dfs(int cur) 
    { 
        if(cur==n+1)print(cur-1); 
        else for(int i=1;i<=n;i++) 
        { 
            if(!visi[i]) 
            { 
                a[cur]=i; 
                visi[i]=1; 
                dfs(cur+1); 
                visi[i]=0; 
            } 
        } 
    } 
    
    int main()
    {
        cin>>n;
        dfs(1);
        puts("");
        return 0;
    }
    9018 1541
     

     


    1542: n个数中取m个数从小到大排列

    题目描述

    n个数中取m个数从小到大排列,详见样例。

    输入

     

    输出

     

    样例输入

    3 2

    样例输出

    1 2
    1 3
    2 3
    

    
    

    当你要输出全排列的时候,你的cur是到N+1的时候结束

     那么cur记录的是当前答案长度是多少 
     那么你要取M个 答案长度就是M
    他是按照字典序输出的 
    你搜索的时候找这个位置上的数是多少肯定是for1到n
    那么先输出的肯定是字典序最小的

    所以就不需要考虑排序的问题啦

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    int n,m;
    bool vis[55];
    int a[55];
    void print(int x)
    {
        for(int i=1;i<x;++i)cout<<a[i]<<" ";
        cout<<a[x];
        puts("");
    }
    void dfs(int cur)
    {
        if(cur==m+1)print(cur-1);
        for(int i=a[cur-1]+1;i<=n;++i) 
    //防止重复搜索比当前数小的数 失去排序作用
        {
            if(!vis[i])
            {
                a[cur]=i;
                vis[i]=1;
                dfs(cur+1);
                vis[i]=0;
            }
        }
    }
    int main()
    {
        cin>>n>>m;
        dfs(1);
        puts("");    
        return 0;
    }
    View Code

     

     

    题目描述

    n个数中取m个数和为偶数的有几种,按字典序输出,详见样例。

    输入

     

    输出

     

    样例输入

    4 2

    样例输出

    1+3=4
    2+4=6

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    bool vis[105];
    int a[105];
    int n,m;
    
    void print(int x)
    {
        int sum=0;
        for(int i=1;i<=x;++i)sum+=a[i];
        if(sum%2!=0)return;//特判和为偶数时输出
        else
        {
            for(int i=1;i<x;++i)printf("%d+",a[i]);
            printf("%d=",a[x]);
            cout<<sum;
            puts("");
        }
    }
    
    void dfs(int cur)
    {
        if(cur==m+1)print(cur-1);
        else 
        {
            for(int i=a[cur-1]+1;i<=n;++i)
            {
                if(!vis[i])
                {
                    a[cur]=i;
                    vis[i]=1;
                    dfs(cur+1);
                    vis[i]=0;
                }
            }
        }
    }
    int main()
    {
        cin>>n>>m;
        dfs(1);
        puts("");    
        return 0;
    }
    View Code

    1544: 整数分解

    题目描述

    输入一个整数n,按照字典序从小到大输出它的分解情况

    输入

     

    输出

     

    样例输入

    4

    样例输出

    1+1+1+1=4
    1+1+2=4
    1+3=4
    2+2=4
    4=4

    他要字典序从小到大 所以本质上我们还是做一个跟全排列类似的过程 只是dfs要记录的东西比较多
    用cur记录当前答案的长度 sum记录当前和 limit记的是当前位置上的数字大小
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    int n,sum;
    int a[105];
    void print(int x,int sum)
    {
        if(sum>n)return;
        else
        {
            for(int i=1;i<x;++i)printf("%d+",a[i]);
            printf("%d=%d",a[x],sum);
            puts("");
        }
    }
    void dfs(int cur,int sum)
    {
        if(sum>=n)print(cur-1,sum);
        else
        {
            for(int i=a[cur-1];i<=n;++i)
            {
                a[cur]=i;
                dfs(cur+1,sum+i);
            }
        }
    }
    int main()
    {
        cin>>n;
        a[0]=1;
        dfs(1,0);
        puts("");    
        return 0;
    }
    a[cur-1]版记录
    #include<iostream> 
    #include<cstdio> 
    #include<cstring> 
    #include<algorithm> 
      
    using namespace std; 
    int n,sum,limit; 
    int a[105]; 
    void print(int x,int sum) 
    { 
        if(sum>n)return; 
        else
        { 
            for(int i=1;i<x;++i)printf("%d+",a[i]); 
            printf("%d=%d",a[x],sum); 
            puts(""); 
        } 
    } 
    void dfs(int cur,int sum,int limit) 
    { 
        if(sum>=n)print(cur-1,sum); 
        else
        { 
            for(int i=limit;i<=n;++i) 
            { 
                a[cur]=i; 
                dfs(cur+1,sum+i,i); 
            } 
        } 
    } 
    int main() 
    { 
        cin>>n; 
        a[0]=1; 
        dfs(1,0,1); 
        puts("");    
        return 0; 
    } 
    limit版



    1545: 字符串回文判定

    题目描述

    读入若干行字符串,判断它是否构成回文。是的话输出"yes",不是的话输出"no"。

    输入的字符串以"end"结束。

    输入

     

    输出

     

    样例输入

    abcbac
    abccba
    abcba
    end

    样例输出

    no
    yes
    yes











    1631: 字符序列

    题目描述

    从三个元素的集合[A,B,C]中选取元素生成一个N个字符组成的序列,使得没有长度为2的相邻子序列相同。例:N = 5时ABCBA是合格的,而序列ABCBC与ABABC是不合格的,因为其中子序列BC,AB是相同的。

    输入

    输入一个整数n,n<=13

    输出

    求出满足条件的N个字符的所有序列总数

    样例输入

    4

    样例输出

    72


    找出所有的长度为n的序列 然后判断是否符合 
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    int n,ans=0;
    int a[20];
    void check()
    {
        for(int i=1;i<=n-2;++i)
        {
            if(a[i]==a[i+2]&&a[i+1]==a[i+3])return;
        }
        ++ans;
    }
    void dfs(int now)
    {
        if(now>n)
        {
            check();return;
        }
        else
        {        
            for(int i=1;i<=3;++i)
            {
                a[now]=i;
                dfs(now+1);
                a[now]=0;
            }
        }
    }
    int main()
    {
        cin>>n;
        dfs(1);
        cout<<ans;
        puts("");    
        return 0;
    }
    View Code
     

    
    


    1674: 回文素数

    题目描述

    一个数如果从左往右读和从右往左读数字是相同的,则称这个数是回文数,如121,1221,15651都是回文数。给定位数n,找出所有既是回文数又是素数的n位十进制数。(注:不考虑超过整型数范围的情况)。

    输入

    位数n,其中1<=n<=5。

    输出

    第一行输出满足条件的素数个数。
    第二行按照从小到大的顺序输出所有满足条件的素数,两个数之间用一个空格区分。

    样例输入

    1

    样例输出

    4
    2 3 5 7



    考虑到首位不能是0 所以首尾都不能是0
    有(fei)点(chang)蠢的想法是 我可以强行暴力的for 0-n 然后特判一下 i=0的时候now=1||n不能搞成0 

    优化一下判断素数的方式

    //别忘了要判断 ①是不是素数 ②是不是构成回文

    //变量名别打错 别问我怎么知道的

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    int n,ans=0;
    int a[20];
    int owo[5005]={};
    void check()
    {
        int res=0,shi=1;
        for(int i=n;i>=1;--i)
        {
            res+=a[i]*shi;
            shi*=10;
        }
        if(res==1)return;
        int pd=n/2;
        for(int i=1;i<=pd;++i)
        {
            if(a[i]!=a[n-i+1])return;
        }
        pd=sqrt(res);
        for(int i=2;i<=pd;++i)
        {
            if(res%i==0)return;
        }
        
        ++ans;
        owo[ans]=res;
    //    cout<<res<<" ";
    }
    void dfs(int now)
    {
        if(now>n)
        {
            check();return;
        }
        else
        {    
            if(now==1)    
            for(int i=1;i<=9;++i)
            {
                {
                    a[now]=i;
                    dfs(now+1);
                    a[now]=0;
                }        
            }
            else    
            for(int i=0;i<=9;++i)
            {
                {
                    a[now]=i;
                    dfs(now+1);
                    a[now]=0;
                }        
            }
        }
    }
    int main()
    {
        cin>>n;
        dfs(1);    
        cout<<ans;
        puts("");
        int pos=1;
        while(owo[pos]!=0)
        {
            printf("%d ",owo[pos]);
            ++pos;
        }
        return 0;
    }
    很慢的乱七八糟版本

     一些优化的可行:

    因为n只有5
    所以直接for一遍判断就好了,比搜索快
     你可以在搜索的时候找回文
    也就是只要搜到长度的一半就好了
    后面直接从前面翻过来 
     对于长度是奇数的要枚举一半+1
    或者 对奇数枚举一半 中间位0-9填

    
    


    1079: 选数

    题目描述

      已知 n 个整数 x1,x2,…,xn,以及一个整数 k(k<n)。从 n 个整数中任选 k 个整数相加,可分别得到一系列的和。例如当 n=4,k=3,4 个整数分别为 3,7,12,19 时,可得全部的组合与它们的和为:
    3+7+12=22  3+7+19=29  7+12+19=38  3+12+19=34。
    现在,要求你计算出和为素数共有多少种。
    例如上例,只有一种的和为素数:3+7+19=29)。

    输入

    键盘输入,格式为:
    n , k (1<=n<=20,k<n)
    x1,x2,…,xn (1<=xi<=5000000)

    输出

     屏幕输出,格式为:
    一个整数(满足条件的种数)。

    样例输入

    4 3
    3 7 12 19

    样例输出

    1
    

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int n,k,a[25],ans=0;
    int zs(int n){
        int i;
        if(n==0||n==1)return 0;
        if(n==2)return 1;
        for(i=2;i*i<=n;i++)if(n%i==0)return 0;
        return 1;
    }
    void dfs(int k,int i,int s){
        if(!k){ans+=zs(s);return;}
        for(i;i<=n;i++)dfs(k-1,i+1,s+a[i]);
    }
    int main()
    {
        memset(a,0,sizeof(a));
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        dfs(k,1,0);
        printf("%d",ans);
        return 0;
    }
    View Code

     早期版

    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    using namespace std;
    int n,k;
    int a[30],choose[30];
    bool vis[30];
    int ans=0;
    void zs(int s)
    {
        if(s==1)return;
        int pd=sqrt(s);
        for(int i=2;i<=pd;++i)if(s%i==0)return;
        ++ans;
    }
    void dfs(int cur,int s,int limit)
    {
        if(cur==k+1)zs(s);
        else for(int i=limit;i<=n;++i) 
        {
            if(!vis[i]) 
            {
    //            choose[cur]=a[i];
                vis[i]=1; 
                dfs(cur+1,s+a[i],i); 
    //            choose[cur]=0;
                vis[i]=0;
            }
        }
    }
    int main()
    {
        cin>>n>>k;
        for(int i=1;i<=n;++i)scanf("%d",&a[i]);
        dfs(1,0,1);
        cout<<ans;
        puts("");
        return 0;
    }
    limit

    一些奇怪的想法//未修正

    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    using namespace std;
    int n,k;
    int a[30],choose[30];
    bool vis[30];
    int ans=0;
    int zs(int s)
    {
        if(s==1)return 0;
        int pd=sqrt(s);
        for(int i=2;i<=pd;++i)if(s%i==0)return 0;
        return 1;
    }
    void dfs(int now,int cur,int sum)
    
    {
    //    if(cur>n)return;
        if(cur<=n&&now<=0)if(zs(sum)){
            ++ans;return;
        }
        dfs(now-1,cur+1,sum+a[cur]);
        dfs(now,cur+1,sum);
    }
    
    int main()
    {
        cin>>n>>k;
        for(int i=1;i<=n;++i)cin>>a[i];
        dfs(k,1,0);
        cout<<ans;
        puts("");
        return 0;
    }
    View Code
    clx资磁
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    
    using namespace std;
    
    int n,m,a[21],sum[200000],tmp,vis[21],t,ans;
    
    /*
     *    n个数中取出m个,n个数分别是a[1-20],
     *    从20个数中选出若干加和,可能的和的数目不会超过200000个,将所有找到的和存在sum内,
     *    tmp用于dfs储存当前的和,
     *    vis用于dfs记录哪些数字已经被选,
     *    t用于记录sum中一共有多少可能的和,
     *    ans用于输出答案.
    */
    
    bool isprime(int x){    //判断质数
        if(x<=1) return false;
        if(x==2) return true;
        int lim=sqrt(x);
        for(int i=2;i<=lim;i++){
            if(x%i==0) return false;
        }
        return true;
    }
    
    int dfs(int p,int q){    //深搜,当前挑选m个数字中的第p个,上一个挑选的数字在n个数字中排第q-1位
        if(p==m+1){                    //到终点,检查,记录
            if(isprime(tmp)){
                sum[++t]=tmp;
            }
            return 0;
        }
        for(int i=q;i<=n;i++){        //只挑在上一个数字之后的数字,也就是比上一个数字大的数字
            if(!vis[i]){
                vis[i]=1;
                tmp+=a[i];
                dfs(p+1,i+1);
                tmp-=a[i];
                vis[i]=0;
            }
        }
        return 0;
    }
    
    int main(){
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            cin>>a[i];
        }
        sort(a+1,a+n+1);            //排序,使得后dfs发现的和一定不比之前发现的来得小,免去排序
        dfs(1,1);
        for(int i=1;i<=t;i++){
            if(sum[i]!=sum[i-1])
                ans++;                //去重统计
        }
        cout<<ans<<endl;
    }
    View Code





  • 相关阅读:
    Java练习 SDUT-1117_求绝对值(选择结构)
    Java练习 SDUT-2561_九九乘法表
    Java练习 SDUT-1160_某年某月的天数
    HDU-1024_Max Sum Plus Plus
    博客园页面DIY
    JDBC
    JavaSE | Lambda| Optional| Stream API
    JavaSE| 网络编程
    JavaSE| 反射
    JavaSE | IO流
  • 原文地址:https://www.cnblogs.com/gc812/p/7069550.html
Copyright © 2011-2022 走看看