深搜整理汇总

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深搜整理汇总相关的知识,希望对你有一定的参考价值。

 时间限制: 1 s
 空间限制: 256000 KB
 题目等级 : 黄金 Gold
 
题目描述 Description

众所周知,LOL这款伟大的游戏,有个叫盖伦的英雄。他的伟大之处在于他特别喜欢蹲草丛阴人(XL:蹲草阴人也算英雄?!CZQ:没办法,个个都是这么玩的)。某日,德玛西亚与诺克萨斯之间又发生了一场战斗,嘉文四世希望盖伦能带领一支K人的德玛西亚军队出战。

战斗发生在召唤师峡谷。整个召唤师峡谷被分割成M行N列的一个矩阵,矩阵中有空地和几片草丛。这几片草丛中有些很大、有些很小。一个1×1的草丛能容纳3个士兵,盖伦坚信蹲草偷袭战术能战胜诺克萨斯军队,所以他希望他的军队能全部蹲进草丛里。当然,为了不影响盖伦的作战,盖伦需要单独霸占连起来的一片草丛(不管草丛有多大)。

技术分享
输入描述 Input Description

第一行M、N、K,表示矩阵的行数、列数和士兵数量。
接下来M行,输入矩阵,‘.‘代表平地,‘*‘代表草丛。

输出描述 Output Description

如果德玛西亚军队和盖伦都能躲进草丛里,则输出“Demacia Win!”,否则输出“Demacia Lose!”

样例输入 Sample Input

3 3 6
.**
...
.*.

样例输出 Sample Output

Demacia Win!

数据范围及提示 Data Size & Hint

1<=m、n<=1500
1<=k<=1500
P.S:这里对于两个1×1的草丛是否连在一起的定义是:对于每个1×1的草从,它与周围(上下左右)的草丛是连在一起的。

思路:先搜索出一共有多少片草丛和每片草丛的面积,从小到大快排,最小的草丛放盖伦,看一下剩下的草丛面积能不能盛放下剩下的小兵

技术分享
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int m,n,k;
int a[1500+10][1500+10];
int dis[1001];
int s[1000];
int head=0,tail=1;
int x[1500+10],y[1500+10],qian[1500+10];
int x0[5]={0,0,0,1,-1},y0[5]={0,1,-1,0,0};
int p=0;
bool f=false;
void init()
  {
      scanf("%d%d%d",&m,&n,&k);
      getchar();
      for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=n;j++)
          {
              char c;
              scanf("%c",&c);
              if(c==.) a[i][j]=0;
              else a[i][j]=1;
          }
        getchar();
        }
  }
void ss()
  {
      for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
          if(a[i][j]==1)
            {
                p++;
                memset(x,0,sizeof(x));
                memset(y,0,sizeof(y));
                memset(qian,0,sizeof(qian));
                head=0;
                tail=1;
                qian[1]=0;
                x[1]=i;
                y[1]=j;
                a[i][j]=0;
                dis[p]++;
                while(head!=tail)
                  {
                      head++;
                      for(int k=1;k<=4;k++)
                        {
                            int xx=x[head]+x0[k],yy=y[head]+y0[k];
                            if(a[xx][yy]==1)
                              {
                                   tail++;
                                   x[tail]=xx;
                                   y[tail]=yy;
                                   qian[tail]=head;
                                   a[xx][yy]=0;
                                   dis[p]++;
                       }
                    }
                }
            }
  }
void sss()
  {
      sort(dis+1,dis+p+1);
      int q=0;
      for(int i=2;i<=p;i++)
        q+=dis[i];
      if(3*q>=k)
        {
            f=true;
            return;
        }
  }
int main()
  {
      init();
      ss();
//     for(int i=1;i<=p;i++) printf("%d ",dis[i]);
      sss();
      if(f==true) printf("Demacia Win!\\n");
      else printf("Demacia Lose!\\n");
    return 0;
  }
View Code
 时间限制: 1 s
 空间限制: 32000 KB
 题目等级 : 白银 Silver
 
 
题目描述 Description

把自然数N分解为若干个自然数之和,输出方案数。

输入描述 Input Description

N,(1≤n≤50)

输出描述 Output Description

方案数

样例输入 Sample Input

5

样例输出 Sample Output

7

数据范围及提示 Data Size & Hint

5 可分为

1 1 1 1 1
1 1 1 2
1 1 3
1 2 2
1 4
2 3

思路:从小到大分解和,深搜就好,思路应该没问题

技术分享
#include<cstdio>

int n,ans;
int a[10000];

void print(int l)
  {
      ans++;
  }

void sousuo(int k,int m)
  {
      for(int i=a[k-1];i<=n;i++)
        if(i<=m)
          {
              a[k]=i;
              m-=i;
              if(m==0)
                {
                    print(k);
                }
            if(m<0)
              return;
            if(m>0)
              {
                sousuo(k+1,m);
                  m+=i;
              }
          }
  }

int main()
  {
      scanf("%d",&n);
      a[0]=1;
      sousuo(1,n);
      printf("%d",ans);
      return 0;
  }
View Code
 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 白银 Silver
 
题目描述 Description

一个朋友网络,如果a认识b,那么如果a第一次收到某个消息,那么会把这个消息传给b,以及所有a认识的人。

如果a认识b,b不一定认识a。

所有人从1到n编号,给出所有“认识”关系,问如果i发布一条新消息,那么会不会经过若干次传话后,这个消息传回给了i,1<=i<=n。

输入描述 Input Description

第一行是n和m,表示人数和认识关系数。

接下来的m行,每行两个数a和b,表示a认识b。1<=a, b<=n。认识关系可能会重复给出,但一行的两个数不会相同。

 

输出描述 Output Description

一共n行,每行一个字符T或F。第i行如果是T,表示i发出一条新消息会传回给i;如果是F,表示i发出一条新消息不会传回给i。

 

样例输入 Sample Input

4 6

1 2

2 3

4 1

3 1

1 3

2 3

样例输出 Sample Output

T

T

T

F

数据范围及提示 Data Size & Hint

n<=1000

1<=a, b<=n

思路:根据已有关系更新所有点之间的关系(比如说已知i和j相连,j和k相连可以推出i和k相连),然后再判断每个点能不能回到自己就好。

技术分享
#include<iostream>
#include<cstdio>
using namespace std;
bool t[1010][1010];
int main()
{
    int n,m,a,b;
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
         scanf("%d%d",&a,&b),t[a][b] = 1;
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
        {
          if(t[j][i]==1)
          for(int k=1;k<=n;k++)
            if(t[i][k]==1)
              t[j][k]=1;
        }
    for(int i=1;i<=n;i++)
    {
        if(t[i][i]==1)
          printf("T\\n");
        else 
          printf("F\\n");
    }
    return 0;
}
View Code
 时间限制: 1 s
 空间限制: 64000 KB
 题目等级 : 白银 Silver
 
题目描述 Description

有一个矩形房间,覆盖正方形瓷砖。每块瓷砖涂成了红色或黑色。一名男子站在黑色的瓷砖上,由此出发,可以移到四个相邻瓷砖之一,但他不能移动到红砖上,只能移动到黑砖上。编写一个程序,计算他通过重复上述移动所能经过的黑砖数。

 

输入描述 Input Description

输入包含多个数据集。一个数据集开头行包含两个正整数W和H,W和H分别表示矩形房间的列数和行数,且都不超过20.
每个数据集有H行,其中每行包含W个字符。每个字符的含义如下所示:
‘.‘——黑砖
‘#‘——红砖
‘@‘——男子(每个数据集仅出现一次)
两个0表示输入结束。

输出描述 Output Description

对每个数据集,程序应该输出一行,包含男子从初始瓷砖出发可到达的瓷砖数。

样例输入 Sample Input

6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#[email protected]#.#.
.#.#####.#.
.#.......#.
.#########.
...........
11 6
..#..#..#..
..#..#..#..
..#..#..###
..#..#..#@.
..#..#..#..
..#..#..#..
7 7
..#.#..
..#.#..
###.###
[email protected]
###.###
..#.#..
..#.#..
0 0

样例输出 Sample Output

45
59
6
13

数据范围及提示 Data Size & Hint

思路:从开始时站立的地方开始深搜就好了,看看能深搜到多少个相连的黑色砖块再输出就好。

技术分享
#include <iostream>
#include <memory.h>
using namespace std;
int w,h,map[21][21],flag[21][21],sw,sh,tot; //map记录砖色,flag统计是否走过 
int opw[]={1,-1,0,0},oph[]={0,0,-1,1};
char tmp;
void dfs(int cw,int ch)
{
 int tmpw,tmph;
 tot++;
 for(int i=0;i<4;i++) {
  tmpw=cw+opw[i];
  tmph=ch+oph[i];
  //不能出界,不能走红砖,不能统计已经走的地方 
  if(tmph<=0||tmph>h||tmpw<=0||tmpw>w||flag[tmpw][tmph]==1||map[tmpw][tmph]==-1) continue;
  flag[tmpw][tmph]=1;
  dfs(tmpw,tmph);
 }
}

int main()
{

 while(true)
 {
  memset(map,0,sizeof(map));
  memset(flag,0,sizeof(flag));
  tot=0; //循环前清变量!! 
  cin>>h>>w;
  if(w==0&&h==0) break;
  for(int i=1;i<=w;i++)
   for(int j=1;j<=h;j++) 
    {cin>>tmp;
     if(tmp==@) {sw=i;sh=j;map[i][j]=1;flag[i][j]=1;}//起点也算一个 
      else if(tmp==#) map[i][j]=-1;
   }
  dfs(sw,sh);
  cout<<tot<<endl;
 }
 return 0;
}
View Code

3411 洪水

 

CodeVS原创

 时间限制: 1 s
 空间限制: 64000 KB
 题目等级 : 青铜 Bronze
题目描述 Description

小浣熊松松和朋友到野外露营,没想到遇上了&pi;年一次的大洪水,好在松松是一只爱观察的小浣熊,他发现露营地的地形和洪水有如下性质:

①露营地可以被看做是一个N*M的矩形方阵,其中左上角坐标为(1,1),右下角坐标为(n,m),每个格子(i,j)都有一个高度h(i,j)。

②洪水送(r,c)开始,如果一个格子被洪水淹没,那这个格子四周比它低(或相同)的格子也会被淹没。

现在松松想请你帮忙算算,有多少个格子不会被淹没,便于他和朋友逃脱。

【原有误数据已删除】

输入描述 Input Description

第一行包含两个整数n,m,表示矩形方阵右下角坐标。

以下n行,每行m个数,第i行第j个数表示格子(i,j)的高度。

最后一行包含两个整数r,c,表示最初被洪水淹没的格子。

输出描述 Output Description

输出仅一行,为永远不会被淹没的格子的数量。

样例输入 Sample Input

3 3

1 2 3

2 3 4

3 4 5

2 2

样例输出 Sample Output

5

思路:从开始点开始搜索四周所有比他低的方向,搜到的符合条件的就标记后再继续深搜,最后统计一下无论如何都不会搜索到的格子的数量就好了

技术分享
#include<cstdio>
#include<iostream>
using namespace std;
int h[1001][1001];
bool g[1001][1001];
int p,n,m;
int a[5]={0,0,0,1,-1};
int b[5]={0,1,-1,0,0};
void input()
  {
      scanf("%d%d",&n,&m);
      p=n*m;
      for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
          scanf("%d",&h[i][j]);
  }
void water(int x,int y)
  {
      g[x][y]=true;
      p--;
      for(int i=1;i<=4;i++)
        if((x+a[i]>=1)&&(x+a[i]<=n)&&(y+b[i]>=1)&&(y+b[i]<=m)&&(h[x+a[i]][y+b[i]]<=h[x][y])&&(g[x+a[i]][y+b[i]]==false))
          water(x+a[i],y+b[i]);
  }
int main()
  {
      int x,y;
      input();
      scanf("%d%d",&x,&y);
      water(x,y);
      printf("%d\\n",p);
      return 0;
  }
View Code

 

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 白银 Silver
题目描述 Description

    给出一个二叉树,输出它的最大宽度和高度。

输入描述 Input Description

第一行一个整数n。

下面n行每行有两个数,对于第i行的两个数,代表编号为i的节点所连接的两个左右儿子的编号。如果没有某个儿子为空,则为0。

输出描述 Output Description

输出共一行,输出二叉树的最大宽度和高度,用一个空格隔开。

样例输入 Sample Input

5

2 3

4 5

0 0

0 0

0 0

样例输出 Sample Output

2 3

数据范围及提示 Data Size & Hint

n<16

默认第一个是根节点

以输入的次序为编号

2-N+1行指的是这个节点的左孩子和右孩子

注意:第二题有极端数据!

          1

          0 0

这题你们别想投机取巧了,给我老老实实搜索!

 思路:这是一道广搜……做错了,思路先不写了

技术分享
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
struct tree{
    int lson,rson;
}d[20];//定义树 
int deep[20],wide[20];//定义宽度,深度 
void build(int now,int fa)
{
    deep[now]=deep[fa]+1;//现在的深度等于父亲的深度+1
    wide[deep[now]]++;//现在深度上的宽度+1
    if(d[now].lson)//如果现在有左儿子
        build(d[now].lson,now);
    if(d[now].rson)
        build(d[now].rson,now);
    return;
}
int main()
{
    int n,l,r;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&d[i].lson,&d[i].rson);//输入编号为i的左儿子和右儿子
    }
    build(1,0);//从头开始
    int w=0,p=0;
    for(int i=1;i<=n;i++)
        w=max(w,wide[i]);
    for(int i=1;i<=n;i++)
        p=max(p,deep[i]);
    printf("%d %d",w,p);
    return 0;
}
View Code

 

1043 方格取数

2000年NOIP全国联赛提高组

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 钻石 Diamond
题目描述 Description

设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下图所示(见样例):

 

某人从图的左上角的A 点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。

此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。

 

技术分享
输入描述 Input Description

输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。

输出描述 Output Description

    只需输出一个整数,表示2条路径上取得的最大的和。

样例输入 Sample Input

      8

      2  3  13

      2  6   6

      3  5   7

      4  4  14

      5  2  21

      5  6   4

      6 3  15

      7 2  14

      0 0  0

样例输出 Sample Output

      67

数据范围及提示 Data Size & Hint
如描述
思路:讲过,思路就不写了……
技术分享
#include<cstdio>
#include<iostream>
using namespace std;
int a[11][11];
int n,x,y,z;
int f[11][11][11][11]; 
int main()
  {
      scanf("%d",&n);
      do
        {
            scanf("%d%d%d",&x,&y,&z);
            a[x][y]=z;
        }while(x!=0&&y!=0&&z!=0);
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
        for(int k=1;k<=n;k++)
          for(int l=1;l<=n;l++)
              {
                  int x1=0,x2=0,x3=0,x4=0;
                  x1=f[i-1][j][k-1][l];
                  x2=f[i-1][j][k][l-1];
                  x3=f[i][j-1][k-1][l];
                  x4=f[i][j-1][k][l-1];
                  f[i][j][k][l]=max(max(x1,x2),max(x3,x4));
                if((i==k)&&(j==l))
                  f[i][j][k][l]+=a[i][j];
                else
                  f[i][j][k][l]+=(a[i][j]+a[k][l]); 
              }
    printf("%d",f[n][n][n][n]);
      return 0;
  }
View Code

 

以上是关于深搜整理汇总的主要内容,如果未能解决你的问题,请参考以下文章

codevs 2801 LOL-盖伦的蹲草计划

codevs 搜索题汇总(黄金级)

Java知识系统回顾整理01基础02面向对象01类和对象

Java 多线程(上)

Java自学-面向对象 类和对象

Flutter 专题26 易忽略的小而巧的技术点汇总 #星光计划2.0#