蓝桥杯,考暴力和搜索,这是众所周知的事情,近几年的题目非常非常的多。
搜索的基本理论:
1、回溯法:当把问题分成若干个步骤并递归求解时,如果当前步骤没有合法选择,则函数将返回上一级递归调用,这种现象就称回溯。
2、路径寻找问题:路径寻找问题可以归结为隐式图的遍历,它的任务是找到一条从初始状态到终止状态的最优路径,而不是像回溯法那样找到一个符合某些要求的解。
常见的两种方法是:深度优先搜索,广度优先搜索。
具体例题分析:
1、模型一:
2016第三题
凑算式
B DEF
A + — + -——— = 10
C GHI
(如果显示有问题,可以参见【图1.jpg】)
这个算式中A~I代表1~9的数字,不同的字母代表不同的数字。
比如:
6+8/3+952/714 就是一种解法,
5+3/1+972/486 是另一种解法。
这个算式一共有多少种解法?
注意:你提交应该是个整数,不要填写任何多余的内容或说明性文字。
#include
using namespace std;
int b[10];
int visited[10]={0};
void dfs(int k,int i);
void sovle();
int sum=0;
int main()
{
int i;
for(i=1;i<=9;i++)
{
dfs(1,i);
visited[i]=0;
}
printf("%d\n",sum);
return 0;
}
void dfs(int k,int i)
{
int j;
visited[i]=1;
b[k]=i;
if(k==9)
{
sovle();
}
else
{
for(j=1;j<=9;j++)
{
if(visited[j]==0)
{
dfs(k+1,j);
visited[j]=0;
}
}
}
}
//先操作,再选择。
void sovle()
{
int i;
int x1,x2,x3;
x1=b[2]*(b[7]*100+b[8]*10+b[9]);
x2=b[3]*(b[4]*100+b[5]*10+b[6]);
x3=(10-b[1])*(b[7]*100+b[8]*10+b[9])*b[3];
if(x1+x2==x3)
{
sum++;
}
}
这道题目,我们看都不用看,果断选择回溯,因为,题意就是对9个数进行排列,然后,找到一个符合标准的排列时,加1.同时回溯法也是解决排列组合的一种很好的方法。但是这道题目麻烦在精度上面,我们必须要对分母进行通分。这个地方是出题人的一个变化的地方,因为以前考的都不用考虑精度,为啥呢?因为就比如2015年的三羊献瑞一样,它是乘法加法运算,算出的都是整数。
当然,我建议在考场直接用c++的next_permutation()这个函数,速度快。
#include
#include
using namespace std;
int main()
{
int x1,x2,x3;
int a[9];
int i;
int sum=0;
for(i=0;i<9;i++)
{
a[i]=i+1;
}
while(next_permutation(a,a+9))
{
x1=a[1]*(a[6]*100+a[7]*10+a[8]);
x2=a[2]*(a[3]*100+a[4]*10+a[5]);
x3=(10-a[0])*(a[2]*(a[6]*100+a[7]*10+a[8]));
if(x1+x2==x3)
{
sum++;
}
}
printf("%d\n",sum);
return 0;
}
2016蓝桥杯第6题:方格填数;
#include
using namespace std;
int graph[3][4]={0};
int visited[10]={0}; //候选集
int sum=0;
void dfs(int k,int i);
int main()
{
int j;
for(j=0;j<=9;j++)
{
dfs(1,j);
visited[j]=0;
}
printf("%d\n",sum);
return 0;
}
void dfs(int k,int i)
{
int x1,x2;
int j;
// int j1,j2;
visited[i]=1;
//k决定了对哪个框进行操作。
//以下就是进行操作。
if(k>=8)
{
x1=2;
x2=k%8;
graph[x1][x2]=i;
//下面是检验;
if(x2==0)
{
if((graph[x1-1][x2]-graph[x1][x2]==1)||(graph[x1-1][x2]-graph[x1][x2]==-1)||(graph[x1][x2]-graph[x1-1][x2+1]==-1)||(graph[x1][x2]-graph[x1-1][x2+1]==1))
{
return;
}
}
else
{
if(x2==1)
{
if((graph[x1-1][x2]-graph[x1][x2]==1)||(graph[x1-1][x2]-graph[x1][x2]==-1)||(graph[x1][x2]-graph[x1][x2-1]==1)||(graph[x1][x2]-graph[x1][x2-1]==-1)||(graph[x1][x2]-graph[x1-1][x2-1]==1)||(graph[x1][x2]-graph[x1-1][x2-1]==-1)||(graph[x1][x2]-graph[x1-1][x2+1]==1)||(graph[x1][x2]-graph[x1-1][x2+1]==-1))
{
return;
}
}
else
{
if((graph[x1-1][x2]-graph[x1][x2]==1)||(graph[x1-1][x2]-graph[x1][x2]==-1)||(graph[x1][x2]-graph[x1-1][x2-1]==1)||(graph[x1][x2]-graph[x1-1][x2-1]==-1)||(graph[x1][x2]-graph[x1][x2-1]==1)||(graph[x1][x2]-graph[x1][x2-1]==-1)||(graph[x1][x2]-graph[x1-1][x2+1]==1)||(graph[x1][x2]-graph[x1-1][x2+1]==-1))
{
return;
}
}
}
}
else
{
if(k>=4)
{
x1=1;
x2=k%4;
graph[x1][x2]=i;
if(x2==0)
{
if((graph[x1-1][x2+1]-graph[x1][x2]==1)||(graph[x1][x2]-graph[x1-1][x2+1]==1))
{
return;
}
}
else
{
if(x2==1)
{
if((graph[x1-1][x2]-graph[x1][x2]==1)||(graph[x1-1][x2]-graph[x1][x2]==-1)||(graph[x1][x2]-graph[x1][x2-1]==-1)||(graph[x1][x2]-graph[x1][x2-1]==1)||(graph[x1][x2]-graph[x1-1][x2+1]==-1)||(graph[x1][x2]-graph[x1-1][x2+1]==1))
{
return;
}
}
else
{
if(x2==2)
{
if((graph[x1][x2]-graph[x1][x2-1]==1)||(graph[x1][x2]-graph[x1][x2-1]==-1)||(graph[x1][x2]-graph[x1-1][x2-1]==1)||(graph[x1][x2]-graph[x1-1][x2-1]==-1)||(graph[x1][x2]-graph[x1-1][x2]==1)||(graph[x1][x2]-graph[x1-1][x2]==-1)||(graph[x1][x2]-graph[x1-1][x2+1]==1)||(graph[x1][x2]-graph[x1-1][x2+1]==-1))
{
return;
}
}
else
{
if((graph[x1][x2]-graph[x1][x2-1]==1)||(graph[x1][x2]-graph[x1][x2-1]==-1)||(graph[x1][x2]-graph[x1-1][x2-1]==1)||(graph[x1][x2]-graph[x1-1][x2-1]==-1)||(graph[x1][x2]-graph[x1-1][x2]==1)||(graph[x1][x2]-graph[x1-1][x2]==-1))
{
return;
}
}
}
}
}
else
{
x1=0;
x2=k%4;
graph[x1][x2]=i;
if(x2==2)
{
if((graph[x1][x2]-graph[x1][x2-1]==1)||(graph[x1][x2]-graph[x1][x2-1]==-1))
{
return;
}
}
else
{
if(x2==3)
{
if((graph[x1][x2]-graph[x1][x2-1]==1)||(graph[x1][x2]-graph[x1][x2-1]==-1))
{
return;
}
}
}
}
}
if(k==10)
{
sum=sum+1;
return;
}
else
{
for(j=0;j<=9;j++)
{
if(visited[j]==0)
{
dfs(k+1,j);
visited[j]=0;
}
}
}
}
//先进行操作,然后,深搜,
此时对我的搜获其实挺大的,因为,以前回溯法解决排列时,大多是算式的题目,最后都回溯到相应k,然后进行一波操作。但是此题,我在做时并没这么做,visited[10]的工作当然一开始就弄了,但是在存数的过程中,存完后我也进行相应的比较了,即验证工作放到了每一步过程中。这种处理方法主要是受蓝桥杯上的lift and throw那道题的影响。of couse ,如果把验证放到最后,也是可以的,那这样的话,直接用c++的模板即可。
#include
using namespace std;
int a[6];
int pd();
int main()
{
int i,j;
for(i=100;i<999;i++)
{
for(j=100;j<999;j++)
{
a[0]=i;
a[1]=j;
a[2]=i*(j%10);
a[3]=i*(j/10%10);
a[4]=i*(j/100%10);
a[5]=i*j;
if(a[2]<100||a[2]>999)
{
continue;
}
if(a[3]<100||a[3]>999)
{
continue;
}
if(a[4]<100||a[4]>999)
{
continue;
}
if(a[5]<10000||a[5]>99999)
{
continue;
}
if(pd())
{
printf("%d\n",a[5]);
break;
}
}
}
return 0;
}
int pd()
{
int t;
int i;
int x;
int b[10]={0};
for(i=0;i<6;i++)
{
t=a[i];
while(t>0)
{
x=t%10;
b[x]++;
if(b[x]>2)
{
return 0;
}
t=t/10;
}
}
return 1;
}
还有注意的一点,注意,对后面这几个进行一个位数的限制。
#include
#include
using namespace std;
int visited[13]={0};
int b[6]={0};//这样做适合排列,不适合组合
int huoxuan[13]={0};
int sum=0;
void dfs(int k,int i);
void dfs1(int i);
void sovle();
int main()
{
dfs(0,0);
printf("%d\n",sum);
return 0;
}
void dfs(int k,int i)
{
int j;
visited[i]=1;
b[k]=i;
if(k==5)
{
sovle();
return;
}
else
{
for(j=1;j<=12;j++)
{
if(visited[j]==0&&j>b[k])
{
dfs(k+1,j);
visited[j]=0;
}
}
}
}
//组合再修改毋庸置疑.
//我下面这种解决方案是很值得思考的,即根本不符合题意。
//往大了取;
void sovle()
{
int i,j;
int x;
int flag=0;
for(i=1;i<13;i++)
{
huoxuan[i]=visited[i];
}
for(i=1;i<13;i++)
{
if(huoxuan[i]==1)
{
break;
}
}
//拿到最小的那个。
dfs1(i);
for(i=1;i<13;i++)
{
if(huoxuan[i]==1)
{
break;
}
}
if(i==13)
{
// for(i=1;i<13;i++)
// {
// if(visited[i]==1)
// {
// printf("%d ",i);
// }
// }
// printf("\n");
sum++;
}
}
void dfs1(int i)
{
int x1,x2;
if(i>=13)
{
return;
}
huoxuan[i]=0;
if(i-4>0)
{
if(huoxuan[i-4]==1)
{
dfs1(i-4);
}
}
if((i-1)%4>0)
{
if(huoxuan[i-1]==1)
{
dfs1(i-1);
}
}
if((i+1)%4!=1)
{
if(huoxuan[i+1]==1)
{
dfs1(i+1);
}
}
if((i+4)<13)
{
if(huoxuan[i+4]==1)
{
dfs1(i+4);
}
}
}