又该我来扯算法来,这两天学了个深搜,各位大神应该听所过撒?
还是得先说下深搜的概念,不知道我学的对不?我认为深搜就是每到一个点都往周围四个方向看一眼,能走就走,不能走...当然你也不许用强的,嘿嘿,然后就是记录这个点已经访问,记住,是记录已经访问后再递归调用,因为不能再走回这里来,同时在递归调用的下一句应该把刚刚标记已经访问的visit还原成没访问,这是关键,不懂得静下心来好好想想就会OK的,然后找到目标就退出好了,这里就说道剪枝,也都听说过吧?感觉好屌好屌的有木有?其实屌个鸡巴,就是在知道可以得出结果就避免多余的递归,减少人力物力财力罢了,哦对了,还有就是在找结果的途中判断这样找下去能不能找到结果,不能的话我不直接over了?就像连连看那个题,只可以转两下,两下转完了要是目标不在这条路径上你认为你会傻哩叭叽浪费时间瞎转悠?
深搜的精华就是递归的灵活调用,都说用栈,其实我觉得不太好,毕竟STL里面的栈的操作都是调用函数,而数组模拟的话麻烦死了,所以就递归直接点,但是要是堆栈段溢出那还是换吧!
深搜显示模仿并制作地图,这个当然是二维数组啦,当然根据需要会要三维数组的,其次是visit数组,刚看时我也会傻哩叭叽认为visit是个STL给的数组,只要直接调用就好了,其实它就是你做的那个地图的仿制品,因为它的作用是区别当前状态时的走过和未走过的点,扯点什么都不如例题来得实在,还是那句老话----聪明人看过例题就能举一反三的。
Prime Ring Problem
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 19807 Accepted Submission(s): 8858
Note: the number of first circle should always be 1.
You are to write a program that completes above process.
Print a blank line after each case.
6 8
Case 1: 1 4 3 2 5 6 1 6 5 2 3 4 Case 2: 1 2 3 8 5 6 7 4 1 2 5 8 3 4 7 6 1 4 7 6 5 8 3 2 1 6 7 4 3 8 5 2
#include <iostream>
#include <cstring>
using namespace std;
int n,sushu[100]={0},huan[10]={0,1},see[22];
//see数组用来标记此数字是否可用,sushu数组是素数表,huan数组是记录素数环
void DFS(int s,int k)
{
int i;
if(s>n)
{
if(sushu[huan[1]+huan[s-1]])
{
for(i=1;i<=n;i++)
{
if(i>1)cout<<"
";
cout<<huan[i];
}cout<<endl;
}
else return;
}
for(i=2;i<=n;i++)
{
if(k) //如果是第一次递归,那么把see数组初始化,不过我现在觉得没意义——!这个可以不要,删除没过的话找我是问
for(int j=1;j<22;j++)
see[j]=1;
if(sushu[i+huan[s-1]]&&see[i])
{
huan[s]=i;//把i装进素数环的相应位置
see[i]=0;
DFS(s+1,0);
//指向下一个空洞-—-!并且用0标记以后的都不是第一次的递归
see[i]=1;
}
}
}
int main (void)
{
int i,j,k,l=1;
for(i=1;i<100;i+=2)sushu[i]=1;
//虽然数量是比较少,不过我还是觉得打表爽一些
sushu[1]=0;sushu[2]=1;
for(i=3;i<100;i++)
for(j=i+i;j<100;j+=i)
sushu[j]=0;
while(cin>>n)
{
cout<<"Case "<<l++<<":"<<endl;
if(n==1)cout<<"1"<<endl;//经过无意间证明,其实不用这一句,而且要的话其实是错的,不信你贴我家代码输入1啊
DFS(2,1); //从环内第二个洞开始填,用1标记第一次的那个递归
cout<<endl;
}
return 0;
}
这个是初学深搜最好的题,不过没用到剪枝,下面再来一个有剪枝的就是了,不过我这个也是我第一次剪枝,大神不许笑类!
Square
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5771 Accepted Submission(s): 1836
3 4 1 1 1 1 5 10 20 30 40 50 8 1 7 2 6 4 4 3 5
yes no yes
#include <iostream>
#include <algorithm>
using namespace std;
int n,s,k,a[22],visit[22]={0};
void DFS(int sum,int x,int
d)
{
if(k||x==3) //匹配好了三个边就行了,用k标记,并剪枝
{
k=1;return;
}
int i;
for(i=d;i<n;i++)
//从d开始,起到剪枝作用,同时避免1-2-3和1-3-2这种重复
{
if(k)return; //把k插入,剪枝
if(!visit[i])
if(sum+a[i]==s)
//加上这个长度后正好是一个边
{
visit[i]=1;
DFS(0,x+1,0);
visit[i]=0;
}
else if(sum+a[i]<s)
//加上这个长度后还不够形成一个边
{
visit[i]=1;
DFS(sum+a[i],x,i+1);
visit[i]=0;
}
}
}
bool cmp(int a,int b)
{
return a<b;
}
int main(void)
{
int m,i;
cin>>m;
while(m--&&cin>>n)
{
for(i=s=0;i<n;i++)
cin>>a[i],s+=a[i];
sort(a,a+n,cmp);
if(s%4==0)
{
s/=4;
k=0;
DFS(0,0,0);
//里面的三个0分别是指当前合成的长度,当前已配好的边数,当前询问到的地点
if(k)cout<<"yes"<<endl;
else cout<<"no"<<endl;
}
else cout<<"no"<<endl;
}
return 0;
}
废话就不说了呢,这都还不会深搜那OrzOrz Orz Orz Orz OrzOrz Orz Orz Orz Orz