搜索 水题&&错误集锦

引子:

本以为搜索的题目老师也不会检查,结果今天早上loli慢悠悠的说:“请同学们提交一下搜索的题目~”,顿时心旌摇曳,却也只能装作镇定自若的样子,点了点头。。

然后就开始了今天的疯狂做题,虽说题目都不是太难,但题多势众啊...

 

刷了那么多题,小有收获,总结+复习一下,也是为了以后避免类似错误(十分直观而又影响巨大的)

所做题目链接:openjudge  2.5  题面不一一附上

 

1.letters

看到这道题,就想到了前几天刚刚学会的STLmap映射,然后没怎么想就敲了一遍代码,结果跑的巨慢无比,然后下去跑操想明白了不用这么麻烦的做法,直接用一个vis数组就是了,看来长时间不做搜索大脑都僵化了。。

其他的就没什么技术含量了,和dfs模板差不多,

细节:1.运算种的i循环0-3就是4次

           2.起始点的vis为true

           3.A-Z ascill码为65-90

代码:

 1 #include<iostream>
 2 #include<cstring>
 3 
 4 using namespace std;
 5 
 6 int fx[4]={0,1,0,-1};
 7 int fy[4]={-1,0,1,0};
 8 int ans=0,d[200][200],n,m;
 9 char a[25][25];bool vis[100];
10 
11 int dfs(int x,int y,int z)
12 {
13     ans=max(ans,z);
14     for(int i=0;i<4;i++)//细节 
15     {
16         int xx=x+fx[i];
17         int yy=y+fy[i];
18         if(xx<=n&&xx>0&&yy<=m&&yy>0&&!vis[a[xx][yy]])
19         {
20             vis[a[xx][yy]]=true;
21             dfs(xx,yy,z+1);
22             vis[a[xx][yy]]=false;
23         }
24     }
25 }
26 int main()
27 {
28     memset(vis,false,sizeof(vis));
29     cin>>n>>m;
30     for(int i=1;i<=n;i++)
31         for(int j=1;j<=m;j++)
32             cin>>a[i][j];
33     vis[a[1][1]]=true;//细节 
34     dfs(1,1,1);
35     cout<<ans<<endl;
36     return 0;
37 }
letters

2&&3.八皇后&&问题

例题八皇后问题引申出的各种问题,比较简单,+注意细节

细节:

      1.横纵循环的次序,外层循环行号,内层循环列号

代码:

 1 #include<iostream>
 2 using namespace std;
 3 int s=0,n,ans[20],h[100]={0},l[100]={0},a[100]={0},b[100]={0},anss[93][20];
 4 void out()
 5 {
 6     s++;
 7     for(int i=1;i<=8;i++)
 8       anss[s][i]=ans[i];  
 9 }
10 int dfs(int k)
11 {
12       //cout<<"12 ";
13       for(int j=1;j<=8;j++)
14         {
15             if((h[j]==0)&&(a[k+j]==0)&&(b[k-j+8]==0))
16             {
17             ans[k]=j;
18             h[j]=1;
19             a[k+j]=1;
20             b[k-j+8]=1;
21             
22             if(k==8)out();
23               else dfs(k+1);
24             h[j]=0;
25             a[k+j]=0;
26             b[k-j+8]=0;
27             }
28         }
29 }
30 int main()
31 {
32     dfs(1);
33     cin>>n;
34     for(int i=1;i<=n;i++)
35     {
36         int x;
37         cin>>x;
38         for(int k=1;k<=8;k++)
39           cout<<anss[x][k];
40         cout<<endl;
41     } 
42 }
八皇后
 1 #include<iostream>
 2 using namespace std;
 3 int s=0,n,ans[20],h[100]={0},l[100]={0},a[100]={0},b[100]={0},anss[93][20];
 4 void out()
 5 {
 6     s++;
 7 //    if(s>4)return ;
 8     cout<<"No. "<<s<<endl;
 9     for(int i=1;i<=8;i++)
10     {
11       for(int j=1;j<=8;j++)
12       {
13           if(ans[j]==i)cout<<1<<" ";
14           else
15             cout<<0<<" ";
16       }
17       cout<<endl;
18     }
19 }
20 int dfs(int k)
21 {
22       //cout<<"12 ";
23       for(int j=1;j<=8;j++)
24         {
25             if((h[j]==0)&&(a[k+j]==0)&&(b[k-j+8]==0))
26             {
27             ans[k]=j;
28             h[j]=1;
29             a[k+j]=1;
30             b[k-j+8]=1;
31             
32             if(k==8)out();
33               else dfs(k+1);
34             h[j]=0;
35             a[k+j]=0;
36             b[k-j+8]=0;
37             }
38         }
39 }
40 int main()
41 {
42 //    cin>>n;//cout<<"123";
43     dfs(1);
44     cin>>n;
45 //    cout<<s;
46     for(int i=1;i<=n;i++)
47     {
48         int x;
49         cin>>x;
50         for(int k=1;k<=8;k++)
51           cout<<anss[x][k];
52         cout<<endl;
53     } 
54 }
八皇后问题

 4.迷宫

这道题是我做openjudge交的最多的一道题,足足交了30次,自己的dfs不知道出现了什么问题,就是不对,总是5分。。。

看了看提问区,五分的解决方法就是判断起点和终点,可是我明明判断了,无奈。。。

唯一的细节就是题目给出的特判,所以收获也就只有好好看题。

5.红与黑

又是一道模板题,注意的地方就是输入的行列是反着来的,

代码:

 

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 
 5 int a[25][25];
 6 int dx[5]={0,0,1,-1},dy[5]={1,-1,0,0};
 7 int m,n,ans=0,xe,ye;
 8 
 9 void dfs(int x,int y)
10 {
11     ans++;
12     a[x][y]=0;
13     for(int i=0;i<=3;i++)
14     {
15         int xx=x+dx[i];
16         int yy=y+dy[i];
17         if(xx<=m&&xx>0&&yy<=n&&yy>0&&a[xx][yy]==1)
18         {
19             a[xx][yy]=0;
20             dfs(xx,yy);
21         }
22     }
23 }
24 
25 int main()
26 {
27     while(cin>>n>>m)
28     {
29         memset(a,0,sizeof(a));
30         ans=0;
31         if(m==0&&n==0)break;
32         for(int i=1;i<=m;i++)
33           for(int j=1;j<=n;j++)
34            {
35             char x;
36             cin>>x;
37             if(x=='.')
38               a[i][j]=1;
39             if(x=='@')
40             {
41               a[i][j]=1;
42               xe=i,ye=j;
43             }
44         }
45         dfs(xe,ye);
46         cout<<ans<<endl;
47     }
48     return 0;
49 }
红与黑

 

6.棋盘问题

这道题第一次交的时候WA0分,主要是因为没好好看题,'#' 的地方才可以放棋子,可是受了上一道题的影响,+盲目自信没试样例2导致了如此惨剧的发生

收获:好好看题X2!!

 

7.取石子游戏

这明明就是递归,不知道为什么放到搜索上来= =

注意每次是谁先手,这里num=1为player1放棋子,player1设为先手拿旗子,

用3目运算符小装了一手,感觉良好,

这道题写了两遍,主要注意取到0获胜的到底是递归上一层的player还是这一层的player,总归最后还是理清了思路。

代码:

 

 1 #include <iostream>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 int f(long long  a,long long  b,int num)
 8 {
 9     if(a<b)swap(a,b);
10     if(b==0)return num==1?2:1;
11     if(a/b>=2)return num;
12     a-=b;
13     return f(a,b,num==1?2:1);
14 }
15 int main()
16 {
17     long long  a,b;
18     while(cin>>a>>b)
19     {
20         if(a==0&&b==0)break;
21         if(f(a,b,1)==1)
22           cout<<"win"<<endl;
23         else
24           cout<<"lose"<<endl;
25     }
26 }
取石子游戏(递归)

 

8.马走日

和dfs模板略有不同的特点可能是八个方向吧,每次走到ans++就好,一次AC

 

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 
 7 int m,n,ans;
 8 int dx[10]={1,1,2,2,-1,-1,-2,-2},dy[10]={2,-2,1,-1,2,-2,1,-1};
 9 int vis[15][15];
10 void dfs(int x,int y,int s)
11 {
12     if(s>n*m)
13     {
14         ans++;
15         return;
16     }
17     for(int i=0;i<8;i++)
18     {
19         int xx=x+dx[i];
20         int yy=y+dy[i];
21         if(xx>=0&&xx<=n-1&&yy>=0&&yy<=m-1)
22         if(!vis[xx][yy])
23         {
24             vis[xx][yy]=1;
25             dfs(xx,yy,s+1);
26             vis[xx][yy]=0;
27         }
28     }
29 }
30 int main()
31 {
32     int u,a,b;
33     cin>>u;
34     while(u--)
35     {
36         memset(vis,0,sizeof(vis));
37         cin>>n>>m>>a>>b;
38         ans=0;
39         vis[a][b]=1;
40         dfs(a,b,2);
41         cout<<ans<<endl;
42     }
43 }
马走日

 

9.单词接龙

记得当时刚来集训,和Juan_feng一起讨论后A掉了这道题(多亏我机智的+1,虽然不知道原理),高兴了一手,

不过听loli讲我们这样做的效率很低,直接把能不能连接,连接后长度增加多少,先预处理出一个二维数组就可以,不用每次都搜索,效率会快很多,深思熟虑后确实是这样,不过代码是之前的版本,有点小懒

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 
 7 int m,n,ans;
 8 int dx[10]={1,1,2,2,-1,-1,-2,-2},dy[10]={2,-2,1,-1,2,-2,1,-1};
 9 int vis[15][15];
10 void dfs(int x,int y,int s)
11 {
12     if(s>n*m)
13     {
14         ans++;
15         return;
16     }
17     for(int i=0;i<8;i++)
18     {
19         int xx=x+dx[i];
20         int yy=y+dy[i];
21         if(xx>=0&&xx<=n-1&&yy>=0&&yy<=m-1)
22         if(!vis[xx][yy])
23         {
24             vis[xx][yy]=1;
25             dfs(xx,yy,s+1);
26             vis[xx][yy]=0;
27         }
28     }
29 }
30 int main()
31 {
32     int u,a,b;
33     cin>>u;
34     while(u--)
35     {
36         memset(vis,0,sizeof(vis));
37         cin>>n>>m>>a>>b;
38         ans=0;
39         vis[a][b]=1;
40         dfs(a,b,2);
41         cout<<ans<<endl;
42     }
43 }
单词接龙

10.分成互质组

一遍ac,小开心一手,

dfs每个数是加入之前的已经建立的组别 or 新开一个组

搜完统计一下组数就是了,

然后还有个剪枝:如果当前组别已经大于目前最优解就return,因为不可能对答案有贡献了,

这道题很怪异的是,我居然自己能把自己的错误卡掉,虽然效率低了一点。。

本来就打算拿部分分的,毕竟从来没有错误再卡掉的操作,结果ac了,有点开心

代码:

 

 1 #include <iostream>
 2 #define re register
 3 #include <algorithm>
 4 
 5 using namespace std;
 6 int n,a[15],vis[15],ans=15,tot[15],z[15][15];
 7 
 8 int gcd(int x,int y)
 9 {
10     if(y==0)return x;
11     else
12       return gcd(y,x%y);
13 }
14 
15 void dfs(int k,int s)
16 {
17     if(s>=ans)return ;
18     if(k>n)
19     {
20         int pd=0;
21         for(int i=0;i<=s;i++)
22           pd+=tot[i];
23         if(pd!=n)return;//卡掉自己不知道为什么会出现的错误 
24         ans=min(ans,s+1);
25         return ;
26     }
27     for(re int i=0;i<=s;i++)
28     {
29         bool flag=true;
30         for(int l=1;l<=tot[i];l++)
31         {
32             if(gcd(z[i][l],a[k])!=1)
33             {
34                 flag=false;
35                 break;
36             }
37         }
38         if(flag)
39         {
40             tot[i]++;
41             z[i][tot[i]]=a[k];
42             dfs(k+1,s);
43             tot[i]--;
44         }
45     }
46     s++;
47 //    cout<<s;
48     z[s][1]=a[k];
49     tot[s]=1;
50     dfs(k+1,s);
51     s--;
52     tot[s]=0;
53 }
54 
55 int main()
56 {
57     cin>>n;
58     for(int i=1;i<=n;i++)
59       cin>>a[i];
60     dfs(1,0);
61 //    cout<<"daole";
62     cout<<ans;
63 }
分成互质组

 

11.分苹果

又是一道递归题,,

在OJ的递归和递推都有这道题,思维难度还是有的

代码:

 1 #include<iostream>
 2 using namespace std;
 3 int put(int x,int y)
 4 {
 5     if((x==1)||(y==1)||(y==0))
 6       return 1;
 7     if(x<y)
 8       return put(x,x); 
 9     if(x==y)
10       return put(x,y-1)+1;
11     if(x>y)
12       return put(x,y-1)+put(x-y,y);
13 }
14 main()
15 {
16     int n,x,y;
17     cin>>n;
18     
19     for (int i=1;i<=n;i++)
20     {
21         cin>>x>>y;
22         cout<<put(x,y)<<endl;
23     }
24     return 0;
25 }
放苹果

 

啊终于写完了,

dfsOJ搜索水题的总结如上

 

posted @ 2018-05-23 21:55  SuperGoodGame  阅读(333)  评论(0编辑  收藏  举报