深搜整理汇总
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深搜整理汇总相关的知识,希望对你有一定的参考价值。
众所周知,LOL这款伟大的游戏,有个叫盖伦的英雄。他的伟大之处在于他特别喜欢蹲草丛阴人(XL:蹲草阴人也算英雄?!CZQ:没办法,个个都是这么玩的)。某日,德玛西亚与诺克萨斯之间又发生了一场战斗,嘉文四世希望盖伦能带领一支K人的德玛西亚军队出战。
战斗发生在召唤师峡谷。整个召唤师峡谷被分割成M行N列的一个矩阵,矩阵中有空地和几片草丛。这几片草丛中有些很大、有些很小。一个1×1的草丛能容纳3个士兵,盖伦坚信蹲草偷袭战术能战胜诺克萨斯军队,所以他希望他的军队能全部蹲进草丛里。当然,为了不影响盖伦的作战,盖伦需要单独霸占连起来的一片草丛(不管草丛有多大)。
第一行M、N、K,表示矩阵的行数、列数和士兵数量。
接下来M行,输入矩阵,‘.‘代表平地,‘*‘代表草丛。
如果德玛西亚军队和盖伦都能躲进草丛里,则输出“Demacia Win!”,否则输出“Demacia Lose!”
3 3 6
.**
...
.*.
Demacia Win!
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; }
把自然数N分解为若干个自然数之和,输出方案数。
N,(1≤n≤50)
方案数
5
7
5 可分为
1 1 1 1 1
1 1 1 2
1 1 3
1 2 2
1 4
2 3
5
思路:从小到大分解和,深搜就好,思路应该没问题
#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; }
一个朋友网络,如果a认识b,那么如果a第一次收到某个消息,那么会把这个消息传给b,以及所有a认识的人。
如果a认识b,b不一定认识a。
所有人从1到n编号,给出所有“认识”关系,问如果i发布一条新消息,那么会不会经过若干次传话后,这个消息传回给了i,1<=i<=n。
第一行是n和m,表示人数和认识关系数。
接下来的m行,每行两个数a和b,表示a认识b。1<=a, b<=n。认识关系可能会重复给出,但一行的两个数不会相同。
一共n行,每行一个字符T或F。第i行如果是T,表示i发出一条新消息会传回给i;如果是F,表示i发出一条新消息不会传回给i。
4 6
1 2
2 3
4 1
3 1
1 3
2 3
T
T
T
F
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; }
有一个矩形房间,覆盖正方形瓷砖。每块瓷砖涂成了红色或黑色。一名男子站在黑色的瓷砖上,由此出发,可以移到四个相邻瓷砖之一,但他不能移动到红砖上,只能移动到黑砖上。编写一个程序,计算他通过重复上述移动所能经过的黑砖数。
输入包含多个数据集。一个数据集开头行包含两个正整数W和H,W和H分别表示矩形房间的列数和行数,且都不超过20.
每个数据集有H行,其中每行包含W个字符。每个字符的含义如下所示:
‘.‘——黑砖
‘#‘——红砖
‘@‘——男子(每个数据集仅出现一次)
两个0表示输入结束。
对每个数据集,程序应该输出一行,包含男子从初始瓷砖出发可到达的瓷砖数。
6 9
....#.
.....#
......
......
......
......
......
#@...#
.#..#.
11 9
.#.........
.#.#######.
.#.#.....#.
.#.#.###.#.
.#.#[email protected]#.#.
.#.#####.#.
.#.......#.
.#########.
...........
11 6
..#..#..#..
..#..#..#..
..#..#..###
..#..#..#@.
..#..#..#..
..#..#..#..
7 7
..#.#..
..#.#..
###.###
[email protected]
###.###
..#.#..
..#.#..
0 0
45
59
6
13
无
思路:从开始时站立的地方开始深搜就好了,看看能深搜到多少个相连的黑色砖块再输出就好。
#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; }
3411 洪水
CodeVS原创
小浣熊松松和朋友到野外露营,没想到遇上了π年一次的大洪水,好在松松是一只爱观察的小浣熊,他发现露营地的地形和洪水有如下性质:
①露营地可以被看做是一个N*M的矩形方阵,其中左上角坐标为(1,1),右下角坐标为(n,m),每个格子(i,j)都有一个高度h(i,j)。
②洪水送(r,c)开始,如果一个格子被洪水淹没,那这个格子四周比它低(或相同)的格子也会被淹没。
现在松松想请你帮忙算算,有多少个格子不会被淹没,便于他和朋友逃脱。
【原有误数据已删除】
第一行包含两个整数n,m,表示矩形方阵右下角坐标。
以下n行,每行m个数,第i行第j个数表示格子(i,j)的高度。
最后一行包含两个整数r,c,表示最初被洪水淹没的格子。
输出仅一行,为永远不会被淹没的格子的数量。
3 3
1 2 3
2 3 4
3 4 5
2 2
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; }
给出一个二叉树,输出它的最大宽度和高度。
第一行一个整数n。
下面n行每行有两个数,对于第i行的两个数,代表编号为i的节点所连接的两个左右儿子的编号。如果没有某个儿子为空,则为0。
输出共一行,输出二叉树的最大宽度和高度,用一个空格隔开。
5
2 3
4 5
0 0
0 0
0 0
2 3
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; }
1043 方格取数
2000年NOIP全国联赛提高组
设有N*N的方格图(N<=10,我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。如下图所示(见样例):
某人从图的左上角的A 点出发,可以向下行走,也可以向右走,直到到达右下角的B点。在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。
此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。
输入的第一行为一个整数N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。
只需输出一个整数,表示2条路径上取得的最大的和。
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
67
#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; }
以上是关于深搜整理汇总的主要内容,如果未能解决你的问题,请参考以下文章