题目描述
小明现在在玩一个游戏,游戏来到了教学关卡,迷宫是一个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>>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>n;
dfs(1);
cout<
题目描述
数独是一种填数字游戏,英文名叫 Sudoku,起源于瑞士,上世纪 70 年代由美国一家数学逻辑游戏杂志首先发表,名为 Number Place,后在日本流行,1984 年将 Sudoku 命名为数独,即 “独立的数字” 的缩写,意思是 “在每一格只有一个数字”。
2004 年,曾任中国香港高等法院法官的高乐德 (Wayne Gould) 把这款游戏带到英国,成为英国流行的数学智力拼图游戏。
玩家需要根据9×9盘面上的已知数字,推理出所有剩余位置的数字,并满足每一行、每一列、每一个粗线九宫格内的数字包含有 1-9 的数字,且不重复。
现在给你一个数独,请你解答出来。每个数独保证有且只有一个解。
输入描述
输入仅一组数据,共 9 行 9 列,表示初始数独(其中 0 表示数独中的空位)
输出描述
输出共 9 行 9 列,表示数独的解。
注意⾏末没有空格。
示例一
输入
5 3 0 0 7 0 0 0 0
6 0 0 1 9 5 0 0 0
0 9 8 0 0 0 0 6 0
8 0 0 0 6 0 0 0 3
4 0 0 8 0 3 0 0 1
7 0 0 0 2 0 0 0 6
0 6 0 0 0 0 2 8 0
0 0 0 4 1 9 0 0 5
0 0 0 0 8 0 0 7 9
输出
5 3 4 6 7 8 9 1 2
6 7 2 1 9 5 3 4 8
1 9 8 3 4 2 5 6 7
8 5 9 7 6 1 4 2 3
4 2 6 8 5 3 7 9 1
7 1 3 9 2 4 8 5 6
9 6 1 5 3 7 2 8 4
2 8 7 4 1 9 6 3 5
3 4 5 2 8 6 1 7 9
思路
题解
#include
using namespace std;
int sudoku[10][10],cnt=0;
vector>v; //存放数组内为 0 的坐标
bool out=false;
bool check(int x,int y){
for(int i=1;i<=9;++i){
if(sudoku[i][y]==sudoku[x][y]&&i!=x) return false; //确定列没有相同的
if(sudoku[x][i]==sudoku[x][y]&&i!=y) return false; //确定行没有相同的
}
int tx=(x-1)/3*3,ty=(y-1)/3*3;
for(int i=tx+1;i<=tx+3;++i){
for(int j=ty+1;j<=ty+3;++j){
if(i==x&&j==y) continue;
if(sudoku[i][j]==sudoku[x][y]) return false; //确定粗线九宫格没有相同的
}
}
return true; //如果前面的都没有返回false,那么就在这返回true
}
void dfs(int dep){
if(dep==cnt){ //先确定最终return的条件,如果所有的 0 都填完了,就return,并且设立out为true使后面退出递归
out=true;
return;
}
int x=v[dep].first,y=v[dep].second;
for(int i=1;i<=9;++i){
sudoku[x][y]=i; //后面的都是经典深搜了,没什么好说的
if(!check(x,y)){
sudoku[x][y]=0;
continue;
}
dfs(dep+1);
if(out) return;
sudoku[x][y]=0;
}
}
int main(){
for(int i=1;i<=9;++i){
for(int j=1;j<=9;++j){
scanf("%d",&sudoku[i][j]);
if(!sudoku[i][j]) ++cnt,v.push_back({i,j});
}
}
dfs(0);
for(int i=1;i<=9;i++){
for(int j=1;j<=9;j++) printf("%d ",sudoku[i][j]); //这里和题目要求的不一样,算是一个小漏洞
printf("\n");
}
}
题目描述
定义一个数字为幸运数字当且仅当它的所有数位都是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;
int l,r,ans=0,flag;
bool check(int num){
stringstream s;
s<<num;
string n=s.str();
for(int i=0;i<n.size();++i){
if(n[i]!=4||n[i]!=7) return false;
}
return true;
}
void next(int num){
if(check(num)){
ans+=num;
return;
}
int i=num;
while(++i){
}
}
int main(){
scanf("%d%d",&l,&r);
next(l);
printf("%d",ans);
}
观看了他人的解法,发现基本都是一个思路
思路
题解
#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;
}
题目描述
输入描述
输出描述
示例一
输入
3
2 4 1
0 0 1
0 0 3
2 5 1
0 0 1
0 0 4
2 5 2
0 0 2
2 0 4
输出
Yes
No
Yes
说明
备注
思路
题解
#include
using namespace std;
typedef long long ll;
int n,h;
ll r;
bool flag,vis[1005];
class Hole{
public:
ll x,y,z;
};
Hole hole[1005];
bool check(Hole cur,Hole next){
return pow(cur.x-next.x,2)+pow(cur.y-next.y,2)+pow(cur.z-next.z,2)<=4*r*r;
}
void dfs(int dep){
if(hole[dep].z+r>=h){
flag=true;
return;
}
for(int i=1;i<=n;++i){
if(!vis[i]&&check(hole[dep],hole[i])) vis[i]=1,dfs(i);
}
}
int main(){
int T,sign;
scanf("%d",&T);
while(T--){
flag=false;
memset(vis,0,sizeof(vis));
scanf("%d%d%lld",&n,&h,&r);
for(int i=1;i<=n;++i) scanf("%lld%lld%lld",&hole[i].x,&hole[i].y,&hole[i].z);
for(int i=1;i<=n;++i) if(hole[i].z<=r) dfs(i);
if(flag) printf("Yes\n");
else printf("No\n");
}
}
题目描述
Due to recent rains, water has pooled in various places in Farmer John’s field, which is represented by a rectangle of N x M (1 <= N <= 100; 1 <= M <= 100) squares. Each square contains either water (‘W’) or dry land (‘.’). Farmer John would like to figure out how many ponds have formed in his field. A pond is a connected set of squares with water in them, where a square is considered adjacent to all eight of its neighbors.
Given a diagram of Farmer John’s field, determine how many ponds he has.
输入描述
Line 1: Two space-separated integers: N and M * Lines 2…N+1: M characters per line representing one row of Farmer John’s field. Each character is either ‘W’ or ‘.’. The characters do not have spaces between them.
输出描述
Line 1: The number of ponds in Farmer John’s field.
示例一
输入
10 12
W…WW.
.WWW…WWW
…WW…WW.
…WW.
…W…
…W…W…
.W.W…WW.
W.W.W…W.
.W.W…W.
…W…W.
输出
3
思路
题解
# include
using namespace std;
bool vis[105][105];
char water_square[105][105];
int ans=0,n,m,dir[8][2]={{0,1},{1,0},{1,1},{-1,0},{0,-1},{-1,-1},{1,-1},{-1,1}};
void dfs(int x,int y){
for(int i=0;i<8;++i){
int xx=x+dir[i][0],yy=y+dir[i][1];
if(!vis[xx][yy]&&water_square[xx][yy]=='W'&&xx>0&&xx<=m&&yy>0&&yy<=n) {
vis[xx][yy]=1,dfs(xx,yy);
}
}
}
int main(){
memset(vis,0,sizeof(vis));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
getchar();
for(int j=1;j<=m;++j) scanf("%c",&water_square[j][i]);
}
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(!vis[j][i]&&water_square[j][i]=='W') vis[j][i]=1,dfs(j,i),ans++;
}
}
printf("%d",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来说有难度(主要是在数学方面上的细节,剪枝算法方面没难度)
乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50。现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它们的长度。给出每段小木棍的长度,编程帮他找出原始木棍的最小可能长度。
输入描述
第一行为一个单独的整数N表示砍过以后的小木棍的总数。第二行为N个用空格隔开的正整数,表示N根小木棍的长度
输出描述
输出仅一行,表示要求的原始木棍的最小可能长度
示例一
输入
9
5 2 1 5 2 1 5 2 1
输出
6
备注
1≤N≤60
思路
题解
#include
using namespace std;
int N,stick[65],total=0,m,len;
bool vis[65],check=false;
void dfs(int which,int current,int rest){ //which——现在是第几根原长木棍,current是刚刚被纳入木棍组合的被砍木棍,rest——此单根木棍还需多长才能达到原长
if(which==m){
check=true;
return;
}
if(rest==0) {
int i=1;
while(!vis[i])++i; //找到一根最大长度能用的木棍(以最大长度为基准)
vis[i]=0;
dfs(which+1,i,len-stick[i]);
vis[i]=1;
}else{
for(int i=current+1;i<=N;++i){
if(vis[i]&&stick[i]<=rest){
vis[i]=0;
dfs(which,i,rest-stick[i]);
vis[i]=1;
if(check) return;
while(stick[i]==stick[i+1])++i;
}
}
}
}
int main(){
scanf("%d",&N);
for(int i=1;i<=N;++i) scanf("%d",&stick[i]),total+=stick[i];
sort(stick+1,stick+1+N,greater());
memset(vis,1,sizeof(vis));
vis[1]=0;
for(len=stick[1];len<=total;++len){
if(total%len!=0) continue;
m=total/len; //m为推理出的原长木棍的数量
dfs(1,1,len-stick[1]);
if(check) {
printf("%d",len);
return 0;
}
}
}