dfs进阶

  当自己以为自己深搜(其实就是暴力啦)小成的时候,发现没有题目的积累还是很难写出程序,自己真的是太年轻了;总结一下就是做此类题看是否需要使用vis数组优化以及继续搜索的条件或者满足答案的条件。以下为2题比较经典的题目:

1、数独

你一定听说过“数独”游戏。 

玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个同色九宫内的数字均含1-9,不重复。
数独的答案都是唯一的,所以,多个解也称为无解。
本图的数字据说是芬兰数学家花了3个月的时间设计出来的较难的题目。但对会使用计算机编程的你来说,恐怕易如反掌了。
本题的要求就是输入数独题目,程序输出数独的唯一解。我们保证所有已知数据的格式都是合法的,并且题目有唯一的解。
格式要求,输入9行,每行9个数字,0代表未知,其它数字为已知。 
输出9行,每行9个数字表示数独的解。
例如:
输入:
005300000 
800000020 
070010500 
400005300 
010070006 
003200080 
060500009 
004000030 
000009700
程序应该输出:
145327698 
839654127 
672918543 
496185372 
218473956 
753296481 
367542819 
984761235 
521839764
再例如,输入:
800000000 
003600000 
070090200 
050007000 
000045700 
000100030 
001000068 
008500010 
090000400
程序应该输出:
812753649 
943682175 
675491283 
154237896 
369845721 
287169534 
521974368 
438526917 
796318452

---------分割线---------

  总结一下题意,在9个3*3的九宫格里填上1~9的数字(不能重复),且9*9的大九宫格每行每列的数字都不能重复。程序总结一下就是81个格子一个一个1~9试着填,中间条件判断是否满足,填完81个格子就代表答案出来了,具体看程序:

 1 #include<stdio.h>
 2 int a[10][10];
 3 int re1(int row,int col,int num)//行列是否重复
 4 {
 5     int i;
 6     for(i=1;i<=9;i++)
 7         if(a[row][i]==num||a[i][col]==num)
 8             return 1;
 9     return 0;
10 }
11 int re2(int row,int col,int num)//小九宫格是否重复
12 {
13     int i,j,x,y;
14     x=(row-1)/3*3+1;
15     y=(col-1)/3*3+1;
16     for(i=x;i<x+3;i++)
17         for(j=y;j<y+3;j++)
18             if(a[i][j]==num)
19                 return 1;
20     return 0;
21 }
22 void dfs(int row,int col)
23 {
24     int i,j;
25     if(row>9)
26     {
27         for(i=1;i<=9;i++)
28         {
29             for(j=1;j<=9;j++)
30                 printf("%d",a[i][j]);
31             printf("
");
32         }
33         exit(0);
34     }
35     if(!a[row][col])
36     {
37         for(i=1;i<=9;i++)
38         {
39             if(!re1(row,col,i)&&!re2(row,col,i))
40             {
41                 a[row][col]=i;
42                 dfs(row+(col+1)/10,(col+1)%10);//下一个格子
43             }
44         }
45         a[row][col]=0;
46     }
47     else
48     {
49         dfs(row+(col+1)/10,(col+1)%10);
50     }
51 }
52 int main()
53 {
54     int i,j;
55     char s[11];
56     for(i=1;i<=9;i++)
57     {
58         scanf("%s",s+1);
59         for(j=1;j<=9;j++)
60             a[i][j]=s[j]-'0';
61     }
62     dfs(1,1);
63     return 0;
64 }

 ---------分割线---------

2、单位分数

1/a 的分数称为单位分数。

可以把1分解为若干个互不相同的单位分数之和。

例如:

1 = 1/2 + 1/3 + 1/9 + 1/18

1 = 1/2 + 1/3 + 1/10 + 1/15

1 = 1/3 + 1/5 + 1/7 + 1/9 + 1/11 + 1/15 + 1/35 + 1/45 + 1/231

等等,类似这样的分解无穷无尽。

我们增加一个约束条件:最大的分母必须不超过30

请你求出分解为n项时的所有不同分解法。

数据格式要求:

输入一个整数n,表示要分解为n项(n<12)

输出分解后的单位分数项,中间用一个空格分开。

每种分解法占用一行,行间的顺序按照分母从小到大排序。

例如,

输入:

4

程序应该输出:

1/2 1/3 1/8 1/24

1/2 1/3 1/9 1/18

1/2 1/3 1/10 1/15

1/2 1/4 1/5 1/20

1/2 1/4 1/6 1/12

再例如,

输入:

5

程序应该输出:

1/2 1/3 1/12 1/21 1/28

1/2 1/4 1/6 1/21 1/28

1/2 1/4 1/7 1/14 1/28

1/2 1/4 1/8 1/12 1/24

1/2 1/4 1/9 1/12 1/18

1/2 1/4 1/10 1/12 1/15

1/2 1/5 1/6 1/12 1/20

1/3 1/4 1/5 1/6 1/20

---------分割线---------

  这题就比较简单啦,连vis数组都不用了,不过题目给的答案和题意不太符合,题意是不超过30,但答案不包括30这个数字。答案不包括30就不包括吧,从第一项2~29开始填,从上一项填的数字到29填当前项,填到第n项且满足条件(通分后相加判断分子分母是否相等,即和是否为1)就是一个分解方法了,具体看代码吧:

 1 #include<stdio.h>
 2 int a[13];
 3 int n;
 4 void dfs(int cur,int t)
 5 {
 6     int i,x,y;
 7     if(cur==n)
 8     {
 9         x=1;y=0;
10         for(i=0;i<n;i++)
11             x*=a[i];
12         for(i=0;i<n;i++)
13             y+=x/a[i];
14         if(x==y)
15         {
16             for(i=0;i<n;i++)
17                 printf("1/%d ",a[i]);
18             printf("
");
19         }
20         return;
21     }
22     else for(i=t;i<30;i++)
23     {
24         a[cur]=i;
25         dfs(cur+1,i+1);
26     }
27 }
28 int main()
29 {
30     scanf("%d",&n);
31     dfs(0,2);
32     return 0;
33 }
原文地址:https://www.cnblogs.com/search-the-universe/p/last_month_2.html