题目描述
小明现在在玩一个游戏,游戏来到了教学关卡,迷宫是一个N*M的矩阵。
小明的起点在地图中用“S”来表示,终点用“E”来表示,障碍物用“#”来表示,空地用“.”来表示。
障碍物不能通过。小明如果现在在点(x,y)处,那么下一步只能走到相邻的四个格子中的某一个:(x+1,y),(x-1,y),(x,y+1),(x,y-1);
小明想要知道,现在他能否从起点走到终点。
输入描述
本题包含多组数据。
每组数据先输入两个数字N,M
接下来N行,每行M个字符,表示地图的状态。
数据范围:
2<=N,M<=500
保证有一个起点S,同时保证有一个终点E.
输出描述
每组数据输出一行,如果小明能够从起点走到终点,那么输出Yes,否则输出No
示例一
输入
3 3
S..
..E
...
3 3
S##
###
##E
输出
Yes
No
解析
题解
#include
using namespace std;
char maze[510][510];
bool vis[510][510];
int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
int N,M;
bool in(int n,int m){
return 0<n&&n<=N&&0<m&&m<=M; //基础的判断,是否会越界
}
bool dfs(int n,int m){
if(maze[n][m]=='E') return true; //return条件
for(int i=0;i<4;++i){
int a=n+dir[i][0],b=m+dir[i][1]; //走上下左右方向
if(!vis[a][b]&&in(a,b)&&maze[a][b]!='#'){ //vis[][]表示是否走过
vis[n][m]=1;
if(dfs(a,b)) return true;
}
}
return false;
}
int main(){
int y,x;
while(cin>>N>>M){
memset(vis,0,sizeof(vis));
getchar();
for(int i=1;i<=N;++i){
for(int j=1;j<=M;++j){
scanf("%c",&maze[i][j]);
if(maze[i][j]=='S') y=i,x=j;
}
getchar();
}
if(dfs(y,x)) printf("Yes\n");
else printf("No\n");
}
}
题目描述
给出一个n×n的国际象棋棋盘,你需要在棋盘中摆放n个皇后,使得任意两个皇后之间不能互相攻击。具体来说,不能存在两个皇后位于同一行、同一列,或者同一对角线。请问共有多少种摆放方式满足条件
输入描述
一行,一个整数n(1≤n≤12),表示棋盘的大小。
输出描述
输出一行一个整数,表示总共有多少种摆放皇后的方案,使得它们两两不能互相攻击。
示例一
输入
4
输出
2
解析
题解
#include
using namespace std;
int n,ans=0,num=0;
bool a=true;
int column[15];
void dfs(int row){ //放进来row行数的参数
if(num==n){
++ans;
return;
}
if(row==n+1) return; //return条件
for(int i=1;i<=n;++i){ //遍历每一列
for(int j=1;j<row;++j){ //遍历这一行以上的所有行(这一行是准备放目前的皇后的行)
if(column[j]==i||(row-j==abs(column[j]-i))) { //column[]是记录之前皇后的位置,key是行数,value是列数
a=false;
break;
}
}
if(a){
column[row]=i; //如果可以放,就标记这个位置
++num; //将已经放了的皇后数+1
dfs(row+1);
--num;
column[row]=0;
}
a=true;
}
}
int main(){
cin>>n;
dfs(1);
cout<<ans;
}
考虑一种简单的正则表达式:
只由 x
(
)
|
组成的正则表达式。
小明想求出这个正则表达式能接受的最长字符串的长度。
例如 ((xx|xxx)x|(x|xx))xx
能接受的最长字符串是: xxxxxx
,长度是
6
6
6。
输入格式
一个由 x()|
组成的正则表达式。输入长度不超过
100
100
100,保证合法。
输出格式
这个正则表达式能接受的最长字符串的长度。
样例输入 #1
((xx|xxx)x|(x|xx))xx
样例输出 #1
6
思路
遇到“)”退出这一层dfs
,结算ans题解
#include
using namespace std;
string str;
int pos,len;
int dfs(){
int num=0,ans=0;
while(pos<len){
if(str[pos]=='('){
pos++;
num+=dfs();
}
else if(str[pos]==')'){
pos++;
break;
}
else if(str[pos]=='|'){
pos++;
ans=max(num,ans);
num=0;
}
else{
num++;
pos++;
}
}
ans=max(num,ans);
return ans;
}
int main(){
cin>>str;
pos=0,len=str.length();
cout<<dfs()<<endl;
}
你有一张某海域
N
×
N
N \times N
N×N 像素的照片,.
表示海洋、 #
表示陆地,如下所示:
.......
.##....
.##....
....##.
..####.
...###.
.......
其中 “上下左右” 四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有 2 2 2 座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
例如上图中的海域未来会变成如下样子:
.......
.......
.......
.......
....#..
.......
.......
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
输入格式
第一行包含一个整数 N N N。 ( 1 ≤ N ≤ 1000 ) (1 \le N \le 1000) (1≤N≤1000)。
以下 N N N 行 N N N 列代表一张海域照片。
照片保证第 1 1 1 行、第 1 1 1 列、第 N N N 行、第 N N N 列的像素都是海洋。
输出格式
一个整数表示答案。
样例输入 #1
7
.......
.##....
.##....
....##.
..####.
...###.
.......
样例输出 #1
1
提示
时限 1 秒, 256M。蓝桥杯 2018 年第九届省赛
思路
其中 "上下左右" 四个方向上连在一起的一片陆地组成一座岛屿
,想着搜到2行n列,或者n行2列的就是会被淹没的。但是这样不知道怎么实现题解
#include
using namespace std;
const int N = 1010;
char g[N][N];
bool st[N][N];
int n;
int total, brink;
const int dx[] = {-1,0,1,0}, dy[] = {0,1,0,-1};
void dfs(int x,int y) {
st[x][y] = true;
total ++;
for(int i = 0;i < 4;i ++)
if(g[x + dx[i]][y + dy[i]] == '.') {
brink ++;
break;
}
for(int i = 0;i < 4;i ++) {
int tx = x + dx[i], ty = y + dy[i];
if(tx < 0 || tx >= n || ty < 0 || ty >= n) continue;
if(g[tx][ty] == '#' && !st[tx][ty]) {
dfs(tx,ty);
}
}
}
int main(){
cin >> n;
for(int i = 0;i < n;i ++) cin >> g[i];
int cnt = 0;
for(int i = 0;i < n;i ++)
for(int j = 0;j < n;j ++)
if(g[i][j] == '#' && !st[i][j]) {
total = brink = 0;
dfs(i,j);
if(total == brink) cnt ++;
}
cout << cnt << endl;
}
班里 N N N 个小朋友,每个人都有自己最崇拜的一个小朋友(也可以是自己)。
在一个游戏中,需要小朋友坐一个圈,每个小朋友都有自己最崇拜的小朋友在他的右手边。
求满足条件的圈最大多少人?
小朋友编号为 1 , 2 , 3 , ⋯ N 1,2,3,⋯N 1,2,3,⋯N。
输入描述
输入第一行,一个整数
N
(
3
<
N
<
1
0
5
)
N(3
接下来一行 N N N 个整数,由空格分开。
输出描述
要求输出一个整数,表示满足条件的最大圈的人数。
样例输入 #1
9
3 4 2 5 3 8 4 6 9
样例输出 #1
4
说明
如下图所示,崇拜关系用箭头表示,红色表示不在圈中。
显然,最大圈是[2 4 5 3] 构成的圈。
运行限制
思路
题解
#include
using namespace std;
const int MAXN=100001;
int worship[MAXN];
bool visit[MAXN];
int n,ans;
void dfs(int k,int step,int goal){
if(visit[k]&&k!=goal) return;
if(visit[k]&&k==goal){
if(step>ans) ans=step;
return;
}
visit[k]=true;
int next=worship[k];
dfs(next,step+1,goal);
visit[k]=false;
}
int main(){
cin>>n;
for(int i=1;i<=n;++i) cin>>worship[i];
for(int i=1;i<=n;++i){
visit[i]=true;
dfs(worship[i],1,i);
}
cout<<ans;
}
题目描述
定义一个数字为幸运数字当且仅当它的所有数位都是4或者7。
比如说,47、744、4都是幸运数字而5、17、467都不是。
定义next(x)为大于等于x的第一个幸运数字。给定l,r,请求出next(l) + next(l + 1) + … + next(r - 1) + next(r)
输入描述
两个整数l和r (1 <= l <= r <= 1000,000,000)。
输出描述
一个数字表示答案
示例一
输入
2 7
输出
33
示例二
输入
7 7
输出
7
首先描述一下,我一开始写的想法:对 l--r 上的每一个数用一遍搜索,然后搜索到一个 “幸运数字” ,然后再剪枝(没写上去)。但是开销是:需要对 l--r 及 r 后面一定数量的数字,统统进行check的遍历(当数字位数长的时候,遍历数字string的开销大)
思路
题解
#include
using namespace std;
typedef long long ll;
ll a[1001000];
ll cnt =0;
void dfs(ll n){
if(n>=44444444444) return;
a[cnt++]=n*10+4;
a[cnt++]=n*10+7;
dfs(n*10+4),dfs(n*10+7);
}
int main(){
ll l,r,pos=0,ans=0;
cin>>l>>r;
dfs(0);
sort(a,a+cnt);
for(ll i=l;i<=r;i++){
while(a[pos]<i) pos++;
ans+=a[pos];
}
cout<<ans;
}
下面的题是含有剪枝策略的深搜题
题目描述
输入描述
有两行,第一行为N(N≤10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M≤20),表示蛋糕的层数为M。
输出描述
仅一行,是一个正整数S(若无解则S=0)。
示例一
输入
100
2
输出
68
备注
附:圆柱公式
体积V=πR2H
侧面积A’=2πRH
底面积A=πR2
思路
别问我怎么想到这3个,一遍一遍地TLE,慢慢迭代出来的
最小为层数,最大为该层的下方那层的半径-1,
,高度范围高度最小为该层层数,最大应该由给出的体积,已知体积和假设的最小体积估算
题解
#include
using namespace std;
int mins[25],minv[25],n,m,ans=INT_MAX; //mins和minv存放估计的最小面积和体积(因为题目中说明了半径和高度为整数,并且由上往下递增,所以可以估计最小)
void dfs(int dep,int r,int h,int s,int v){ //传入的dep是要计算的那层层数,而r,h是上一层的半径和高度
if(dep==0){
if(v==n) ans=min(ans,s);
return;
}
int max_height=h;
if(s+mins[dep-1]>=ans) return;
if(v+minv[dep-1]>n) return;
if(2*(n-v)/r+s>=ans) return;
for(int i=r-1;i>=dep;--i){
if(dep==m) s=i*i;
max_height=min(h-1,(n-minv[dep-1])/i/i); //这里是确定高度的上界,n-minv[]……得到的是由估算最小体积计算出的高度。因为h-1是当前层数不可逾越的最大高度,而n-minv……同样也是不可逾越的最大高度,所以取两个中较小那个
for(int j=max_height;j>=dep;--j) dfs(dep-1,i,j,s+2*i*j,v+i*i*j);
}
}
int main(){
scanf("%d%d",&n,&m);
memset(mins,0,sizeof(mins));
memset(minv,0,sizeof(minv));
for(int i=1;i<=m;++i) mins[i]=mins[i-1]+2*i*i,minv[i]=minv[i-1]+i*i*i;
dfs(m,n,n,0,0);
if(ans==INT_MAX) printf("-1");
else printf("%d",ans);
}
这道题comprehensively来说有难度(主要是在数学方面上的细节,剪枝算法方面没难度)