今天上午还是练习深度优先搜索的几道例题,虽然这种方法的原理理解了,但做题还是做不出来,老是出错,真的是“纸上得来终觉浅”啊。还有今天下午第一次做比赛,做到怀疑人生......可能是这几天深搜做多了,见着题就往深搜方面想,结果把一道递推题和数论题都按深搜做的,加上水平有限,没能AC。这个周集中突破dfs!!!
还是附上今天上午练的dfs代码:
eg1.任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和。
当n=7共14种拆分方法:
7=1+1+1+1+1+1+1
7=1+1+1+1+1+2
7=1+1+1+1+3
7=1+1+1+2+2
7=1+1+1+4
7=1+1+2+3
7=1+1+5
7=1+2+2+2
7=1+2+4
7=1+3+3
7=1+6
7=2+2+3
7=2+5
7=3+4
total=14
#include<iostream>
using namespace std;
int a[10001]={1};//a[]用来保存每个拆分成的数
int n,total;//n代表要拆分的数,total代表方案总数
int search(int,int);//搜索
int print(int);//打印结果
int main()
{
cin>>n;
search(n,1);
cout<<"total="<<total<<endl;
return 0;
}
int print(int t)
{
cout<<n<<"=";
for(int i=1;i<=t-1;i++)
cout<<a[i]<<"+";
cout<<a[t]<<endl;
total++;
}
int search(int s,int t)//t代表当前拆分成的数的序号,s代表当前要拆分的数
{
int i;
for(i=a[t-1];i<=s;i++)//i表示拆分成的数,i大于等于它的前一个数并且小于等于当前的要拆分的数
if(i<n)//当前的数i要大于等于前一个数且小于n,这个条件是为了排除i=n这个情况,因为n=n这一情况不符合要求
{
a[t]=i;//保存当前拆分的数i
s-=i;//s减去当前拆分的数i,s将继续拆分
if(s==0)print(t);
else search(s,t+1);//当s>0,继续搜索
s+=i;//回溯:加上拆分的数,以便产生所有可能的拆分
}
}
eg2.数的排列
设有n个整数的集合{1,2,…,n},从中取出任意r个数进行排列(r<n),试列出所有的排列。
#include<iostream>
#include<iomanip>
using namespace std;
int n,r;
int a[10001];//记录数字
bool b[10001]={0};//记录该数字是否已被应用,未被应用记为0
int search(int);
int print();
int main()
{
cin>>n>>r;
search(1);//从k=1开始搜索,直到k=r停止
return 0;
}
int search(int k)
{
for(int i=1;i<=n;i++)//在搜索的每一层都有n个子树,共有k层(即k步)
if(!b[i])//如果数i没被应用
{
a[k]=i;//第k步保存数i
b[i]=1;
if(k==r)print();
else search(k+1);
b[i]=0;
}
}
int print()
{
for(int i=1;i<=r;i++)
cout<<setw(3)<<a[i];
cout<<endl;
}
DFS的题,题解能看懂,但要是自己做还真做不出来,明天接着练!还有希望后天的练习赛别像今天这样惨...