DFS深度优先遍历题型大总结

三羊献瑞

public class test0406 {
//祥瑞生辉三洋献气 01234567
    public static int a[]=new int[8];
    public static int visited[]=new int[10];
    public static void dfs(int cur){
        if(cur==8){
            int x,y,z;
            x=a[0]*1000+a[1]*100+a[2]*10+a[3];
            y=a[4]*1000+a[5]*100+a[6]*10+a[1];
            z=a[4]*10000+a[5]*1000+a[2]*100+a[1]*10+a[7];
            if(x+y==z){
                System.out.println(y);
            }
            return;
        }
        for(int i=0;i<=9;i++){
            if(cur==0&&i==0)
                continue;
            if(cur==4&&i!=1)
                continue;
            if(visited[i]==0){
                visited[i]=1;
                a[cur]=i;
                dfs(cur+1);
                visited[i]=0;
            }
        }
    }
    public static void main(String[] args){
        dfs(0);
    }
}

牌型种数

小明被劫持到X赌城,被迫与其他3人玩牌。
一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。
这时,小明脑子里突然冒出一个问题:
如果不考虑花色,只考虑点数,也不考虑自己得到的牌的先后顺序,自己手里能拿到的初始牌型组合一共有多少种呢?
思路:循环遍历每个点数所选择的张数,每个点数最多可以选4张,最少可以选0张即不选,每当牌总数达到13张则计数。
变量cur代表对1-13这13个牌种的遍历,每个牌种的选择从0到4,最终需要13张全部遍历完成
变量sum代表这十三个牌种的总和,最后需要=13

public class test0406oj2 {
    public static int N=0;  
    public static void dfs(int cur,int sum){
        if(cur>13)
            return;
        if(sum>13)
            return;
        if(sum==13&&cur==13){
            N++;
        }
        for(int i=0;i<=4;i++){
            dfs(cur+1,sum+i);
        }
    }
    public static void main(String[] args){
        dfs(0,0);
        System.out.println(N);
    }
}

寒假作业

现在小学的数学题目也不是那么好玩的。
看看这个寒假作业:

□ + □ = □
□ - □ = □
□ × □ = □
□ ÷ □ = □

每个方块代表1~13中的某一个数字,但不能重复。
比如:
6 + 7 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5

以及:
7 + 6 = 13
9 - 8 = 1
3 * 4 = 12
10 / 2 = 5

就算两种解法。(加法,乘法交换律后算不同的方案)
你一共找到了多少种方案?
每个数的选择范围1到13 进行比较
这种方法用时较长

public class oj3 {
    public static int ans=0;
    public static int a[]=new int[20];
    public static int visited[]=new int[20];
    public static void dfs(int cur){
        if(cur>12){
            if((a[1]+a[2]==a[3])&&
                    (a[4]-a[5]==a[6])&&
                    (a[7]*a[8]==a[9])&&
                    (a[11]*a[12]==a[10]))
                ans++;
                return;         
        }

        for(int i=1;i<=13;i++){
            if(visited[i]==0){
                visited[i]=1;
                a[cur]=i;
                dfs(cur+1);
                visited[i]=0;
            }
        }
    }
    public static void main(String[] args){
        dfs(1);
        System.out.println(ans);
    }
}

对3,6,9均进行判断,用时较短

public class test0602 {
    public static int a[]=new int[14];
    public static int visit[]=new int[14];
    public static int sum=0;
    public static void main(String[] args){
        dfs(1);
        System.out.println(sum);
    }


    public static void dfs(int n)  
    {  
        if(n>3 && a[1]+a[2]!=a[3])            
            return;  
        if(n>6 && a[4]-a[5]!=a[6])           
            return;  
        if(n>9 && a[7]*a[8]!=a[9])               
            return;  
        if(n>12 && a[12]*a[11]==a[10])        
        {  
            sum++;  
            return;  
        }  

        for(int i=1;i<14;i++)  
        {  
            if(visit[i]==0)  
            {  
                visit[i]=1;  
                a[n]=i;  
                dfs(n+1);  
                visit[i]=0;  
            }  
        }  
        return;  
    }  
}

剪邮票

如图1, 有12张连在一起的12生肖的邮票。现在你要从中剪下5张来,要求必须是连着的。


图1.jpg

(仅仅连接一个角不算相连)比如,【图2.jpg】,【图3.jpg】中,粉红色所示部分就是合格的剪取。


图2.jpg

图3.jpg

请你计算,一共有多少种不同的剪取方法。请填写表示方案数目的整数。
若要剪出的纸片相连,必须是某个数的上方下方左方和右方,而该纸片一共有3行4列,并且数字是连续的,我们可以通过-4,+4,-1,+1 来分别表示上下左右,但是我们发现4,8,12号数字+1到了另一行的另外一边而不连续,5,9两个数字-1也是同样,所以我们把第二行换成6,7,8,9 第三行换成11,12,13,14,从而避免出现以上的情况如图所示

public class Seven {
   public static int count = 0 ;       //记录总的方案数
   public static int cut[] = new int[5] ;  //从所有邮编中选出5张从小到大号码不同的邮票,存入该数组中避免选取的邮票出现重复
   public static int isVisit[] = new int[5] ;  //判断取出的5张邮票是否已经访问
   public static int b[] = {+1,-1,+5,-5} ; //判断取出的5张邮票是否相连,+1表示与右边相连,-1表示左边,+5表示下面,-5表示上面
   public static void main(String[] args) {
       int stamp[] = new int[12] ; //定义所有邮票号码

       for(int i = 1,k = 1 ; i <= 12 ; i++){   //初始化所有的邮票号码为{1,2,3,4,6,7,8,9,11,12,13,15}
           stamp[i-1] = k++ ;
           if(i % 4 == 0){
               k ++ ;
           }
       }

       for(int a = 0 ; a < 12 ; a++){  //通过for循环取出5张邮票,号码从小到大
           for(int b = a + 1 ; b < 12 ; b++){
               for(int c = b + 1 ; c < 12 ; c ++){
                   for(int d = c + 1 ; d < 12 ; d++){
                       for(int e = d + 1 ; e < 12 ; e ++){
                           //将取出的邮票存入cut数组中,保存
                           cut[0] = stamp[a] ;
                           cut[1] = stamp[b] ;
                           cut[2] = stamp[c] ;
                           cut[3] = stamp[d] ;
                           cut[4] = stamp[e] ;
                           for(int i = 0 ; i < 5 ; i++){   //初始化取出的邮票都为未访问状态
                               isVisit[i] = 0 ;
                           }
                           //开始访问
                           isVisit[0] = 1 ;    //另cut数组头为已访问状态
                           //从cut数组头开始,判断该方案是否可行
                           find(0) ;   
                           int flag = 1 ;  //当flag为1时可行,否则不可行
                           for(int j = 0 ; j < 5 ; j++){
                               if(isVisit[j] == 0){    //只要一个数未访问到则说明不可行
                                   flag = 0 ;
                                   break ;
                               }
                           }
                           if(flag == 1){
                               count ++ ;
                           }
                       }
                   }
               }
           }
       }
       System.out.println(count);

   }
   private static void find(int index) {
       for(int i = 0 ; i < 4 ; i++){   //计算出cut[index]上下左右的数
           int tempCut = cut[index] + b[i] ;
           if(tempCut < 1 || tempCut > 14 || tempCut ==5 ||tempCut==10){
               continue ;
           }
           for(int k = 0 ; k < 5 ; k++){   
               if(isVisit[k]==0&&cut[k]==tempCut){//如果cut数组里有数与tempCut匹配的话,继续查询下一个
                   isVisit[k] = 1 ;
                   find(k) ;
               }
           }
       }
   }
}

神奇算式

由4个不同的数字,组成的一个乘法算式,它们的乘积仍然由这4个数字组成。
比如:
210 x 6 = 1260
8 x 473 = 3784
27 x 81 = 2187
都符合要求。
如果满足乘法交换律的算式算作同一种情况,那么,包含上边已列出的3种情况,一共有多少种满足要求的算式。
暴力方法:


import java.util.ArrayList;
import java.util.Scanner;

public class shenqisuanshibaoli {

    public static int ans1=0,ans2=0;//1对3和2对2两种情况,2对2会出现交换律,最后记得除以二
    public static boolean testself(int n){//使自身不重复
        String s=n+"";
        for(int i=1;i<s.length();i++){
            for(int j=0;j<i;j++)
            if(s.charAt(i)==s.charAt(j)){
                return false;
            }
        }
        return true;
    }
    public static boolean testnorepeat(int a,int x){//使A和B两个乘数不重复
        String s1=a+"";
        String s2=x+"";
        ArrayList<Character> arr=new ArrayList<>();
        for(int i=0;i<s1.length();i++)
            arr.add(s1.charAt(i));
        for(int i=0;i<s1.length();i++)
            if(s2.indexOf(arr.get(i))!=-1){
                return false;
            }
        return true;
    }
    public static boolean testrepeat(int a,int b,int x){//结果出现重复
        String s1=a+"";
        String s2=b+"";
        String s3=x+"";
        ArrayList<Character> arr=new ArrayList<>();
        for(int i=0;i<s1.length();i++)
            arr.add(s1.charAt(i));
        for(int i=0;i<s2.length();i++)
            arr.add(s2.charAt(i));
        if(s3.length()!=4)
            return false;
        for(int i=0;i<s3.length();i++){
            if(s3.indexOf(arr.get(i))==-1){
                return false;
            }           
        }
        return true;
    }
    public static void main(String args[]){
        for(int a=1;a<10;a++)
            for(int b=100;b<999;b++){
                if(testself(b)&&testnorepeat(a,b)){
                    int x=a*b;
                    if(testself(x)&&testrepeat(a,b,x)){
                        System.out.println(a+"*"+b+"=="+x);
                        ans1++;
                    }
                }
            }
        System.out.println("------------------------");
        for(int a=10;a<99;a++)
            for(int b=10;b<99;b++){
                if(testself(a)&&testself(b)&&testnorepeat(a,b)){
                    int x=a*b;
                    if(testself(x)&&testrepeat(a,b,x)){
                        System.out.println(a+"*"+b+"=="+x);
                        ans2++;
                    }
                }
            }
        System.out.println(ans1+ans2/2);
    }
}

dfs方法


public class shenqisuanshi {
    public static int ans=0,ans2=0;
    public static int a[]=new int[10];
    public static int visited[]=new int[10];
    public static boolean testrepeat(){
        int left=a[0];
        int right=a[1]*100+a[2]*10+a[3];
        int answer=left*right;
        String s1=left+"";
        String s2=right+"";
        String s3=answer+"";
        ArrayList<Character> arr=new ArrayList<>();
        for(int i=0;i<s1.length();i++)
            arr.add(s1.charAt(i));
        for(int i=0;i<s2.length();i++)
            arr.add(s2.charAt(i));
        if(s3.length()!=4)
            return false;
        for(int i=0;i<s3.length();i++){
            if(s3.indexOf(arr.get(i))==-1){
                return false;
            }           
        }
        return true;
    }
    public static boolean testrepeat2(){
        int left=a[0]*10+a[1];
        int right=a[2]*10+a[3];
        int answer=left*right;
        String s1=left+"";
        String s2=right+"";
        String s3=answer+"";
        ArrayList<Character> arr=new ArrayList<>();
        for(int i=0;i<s1.length();i++)
            arr.add(s1.charAt(i));
        for(int i=0;i<s2.length();i++)
            arr.add(s2.charAt(i));
        if(s3.length()!=4)
            return false;
        for(int i=0;i<s3.length();i++){
            if(s3.indexOf(arr.get(i))==-1){
                return false;
            }           
        }
        return true;
    }
    
    public static void dfs(int cur){
        if(cur>3){
            if(testrepeat()){
                System.out.println(a[0]+"*"+a[1]+a[2]+a[3]);
                ans++;
            }
            if(testrepeat2()){
                System.out.println(a[0]+""+a[1]+"*"+a[2]+a[3]);
                ans2++;
            }
            return;
        }
        for(int i=0;i<10;i++){
//          if(cur==1&&i==0)
//              continue;
            if(visited[i]==0){
                visited[i]=1;
                a[cur]=i;
                dfs(cur+1);
                visited[i]=0;
            }
        }
    }
    public static void main(String[] args){
        dfs(0);
        System.out.println(ans+ans2/2);
    }
}

李白打酒

话说大诗人李白,一生好饮。幸好他从不开车。
一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:
无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。
这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。
请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。
变量只有A,B 每次决定添加A还是B,设置限制条件,5,10,15,因为只有2个所以不进行for循环直接递归调用。

public class libaidajiu {

    public static char[] a=new char[20];
    public static int ans=0;
    public static void dfs(int cur,int dian,int hua,int jiu){
        if(dian>5)
            return;
        if(hua>10)
            return;
        if(cur==15){
            if(dian==5&&hua==10&&a[14]=='b'&&jiu==0){
                for(int i=0;i<=14;i++)
                    System.out.print(a[i]);
                System.out.println();
                ans++;
            }
            return;
        }
        a[cur]='a';
        dfs(cur+1,dian+1,hua,jiu*2);
        a[cur]='b';
        dfs(cur+1,dian,hua+1,jiu-1);
    }
    
    public static void main(String[] args){
        dfs(0,0,0,2);
        System.out.println(ans);
    }
}

这两者思路是一样的,贴上来这种手动更改的更方便理解。将需要来回变化的变量放参数中明显更方便。(如果不理解可以看下一题)


奇怪的比赛

某电视台举办了低碳生活大奖赛。题目的计分规则相当奇怪:
每位选手需要回答10个问题(其编号为1到10),越后面越有难度。答对的,当前分数翻倍;答错了则扣掉与题号相同的分数(选手必须回答问题,不回答按错误处理)。
每位选手都有一个起步的分数为10分。
某获胜选手最终得分刚好是100分,如果不让你看比赛过程,你能推断出他(她)哪个题目答对了,哪个题目答错了吗?
如果把答对的记为1,答错的记为0,则10个题目的回答情况可以用仅含有1和0的串来表示。例如:0010110011 就是可能的情况。
你的任务是算出所有可能情况。每个答案占一行。


public class qiguadebisai {
    public static int[] a=new int[20];
    public static int ans=0;
    public static void dfs(int cur,int score){
        if(cur>10){
            if(score==100){
                for(int i=1;i<cur;i++)
                    System.out.print(a[i]);
                System.out.println();
                ans++;
            }
            return;
        }
        a[cur]=1;
        dfs(cur+1,score*2);
        a[cur]=0;
        dfs(cur+1,score-cur);
    }
    public static void main(String[] args){
        dfs(1,10);
        System.out.println(ans);
    }
}

猜算式

public class caisuanshi {
    static int[] aaa=new int[10];
    public static void main(String[] args){
        for(int i=100;i<=999;i++)
            for(int j=100;j<=999;j++){
                int x=i*j;
                int a=i*(j%10);
                int b=i*((j/10)%10);
                int c=i*(j/100);
                for(int p=0;p<aaa.length;p++){
                    aaa[p]=0;
                }
                if(a>=1000||b>=1000||c>=1000||x>=100000||a<100||b<100||c<100)
                    continue;
                check(x);check(i);check(j);
                check(a);check(b);check(c);
                boolean flag=true;
                for(int p=0;p<aaa.length;p++){
                    if(aaa[p]!=2){
                        flag=false;
                        break;
                    }
                }
                if(flag==true)
                    System.out.println(x);
            }
    }
    
    public static void check(int n){
        while(n>0){
            aaa[n%10]++;
            n=n/10;
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容

  • 你的数学直觉怎么样?你能凭借直觉,迅速地判断出谁的概率大,谁的概率小吗?下面就是 26 个这样的问题。如果你感兴趣...
    cnnjzc阅读 6,439评论 0 12
  • 哪是那么容易好得了得。现在很多时候,也有被那个影响到的呀。有一些过激反应吧。
    何莫负阅读 59评论 0 0
  • 我不是一个超级英雄迷,说实话对这类片子没有什么期待。有一次看见微博里一张图说是“漫威的第一位女英雄”,原PO哈哈大...
    Ourdays阅读 395评论 0 0