山峰和山谷
题目描述
FGD小朋友特别喜欢爬山,在爬山的时候他就在研究山峰和山谷。
为了能够对旅程有一个安排,他想知道山峰和山谷的数量。
给定一个地图,为FGD想要旅行的区域,地图被分为 n×n 的网格,每个格子 (i,j) 的高度 w(i,j) 是给定的。
若两个格子有公共顶点,那么它们就是相邻的格子,如与 (i,j) 相邻的格子有(i−1,j−1),(i−1,j),(i−1,j+1),(i,j−1),(i,j+1),(i+1,j−1),(i+1,j),(i+1,j+1)。
你的任务是,对于给定的地图,求出山峰和山谷的数量,如果所有格子都有相同的高度,那么整个地图即是山峰,又是山谷。
输入描述
第一行包含一个正整数 n,表示地图的大小(1<=n<=1000)。
接下来一个 n×n 的矩阵,表示地图上每个格子的高度 w(0<=w<=1000000000)。
输出描述
共一行,包含两个整数,表示山峰和山谷的数量。
样例输入
5 8 8 8 7 7 7 7 8 8 7 7 7 7 7 7 7 8 8 7 8 7 8 8 8 8
样例输出
2 1
提示
山峰定义为:一个连通块,对于每一个属于此连通块的点,有:这个点周围所有与它八连通的点值都比这个点的值要小。
山谷定义为:一个连通块,对于每一个属于此连通块的点,有:这个点周围所有与它八连通的点值都比这个点的值要大。
代码
#include<iostream>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e3+10;
int dx[8]={-1,-1,-1,0,0,1,1,1};
int dy[8]={-1,0,1,-1,1,-1,0,1};
int f1,f2,c1,c2;
int a[N][N],n,vis[N][N];
void dfs(int x,int y){
vis[x][y]=1;
for(int i=0;i<8;i++){
int nx=x+dx[i];
int ny=y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=n){
if(a[nx][ny]<a[x][y]){
f1=1;
}
if(a[nx][ny]>a[x][y]){
f2=1;
}
if(vis[nx][ny]==0&&a[nx][ny]==a[x][y]){
dfs(nx,ny);
}
}
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(vis[i][j]==0){
f1=0;
f2=0;
dfs(i,j);
if(f1==1&&f2==0){
c1++;
}
if(f1==0&&f2==1){
c2++;
}
if(f1==0&&f2==0){
c1++;
c2++;
}
}
}
}
cout<<c1<<" "<<c2;
return 0;
}
沼泽问题
题目描述
达达要穿过一片N*N(2<=N<10)的沼泽地,入口和出口分别在左上角和右下角。沼泽地中的路分别放0和1,0表示可以走的道路,1表示不能走的泥沼,入口和出口处肯定是0。沼泽地行走的规则如下所示:即从某点开始,有四个方向可走,前进方格中数字为0时表示可通过,为1时表示不可通过,要另找路径。 找出所有从入口(左上角)到出口(右下角)的路径(不能重复),输出路径总数,如果无法到达,则输出0。
输入描述
第一行输入一个整数N,代表沼泽的的边长。
第2-N+1行输入每行输入N个整数(0 1),用来描述沼泽地地形
输出描述
一个整数,代表所有不重复的路径数量
样例输入
3 000 010 000
样例输出
2
代码
#include<iostream>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int N=15;
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
int n,vis[N][N],cnt;
char a[N][N];
void dfs(int x,int y){
vis[x][y]=1;
if(x==n&&y==n){
cnt++;
vis[x][y]=0;
return ;
}
for(int i=0;i<4;i++){
int nx=x+dx[i];
int ny=y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=n&&vis[nx][ny]==0&&a[nx][ny]=='0'){
dfs(nx,ny);
vis[nx][ny]=0;
}
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
}
dfs(1,1);
cout<<cnt;
return 0;
}
走迷宫
题目描述
有一个n*m格的迷宫(表示有n行、m列),其中有可走的也有不可走的,如果用1表示可以走,0表示不可以走,文件读入这n*m个数据和起始点、结束点(起始点和结束点都是用两个数据来描述的,分别表示这个点的行号和列号)。现在要你编程找出所有可行的道路,要求所走的路中没有重复的点,走时只能是上下左右四个方向。如果一条路都不可行,则输出相应信息(用-l表示无路)。
请统一用左上右下的顺序拓展,也就是 (0,-1),(-1,0),(0,1),(1,0)
输入描述
第一行是两个数n,m( 1 < n , m < 15 ),接下来是n行m列由1和0组成的数据,最后两行是起始点和结束点。
输出描述
所有可行的路径,描述一个点时用(x,y)的形式,除开始点外,其他的都要用“->”表示方向。
如果没有一条可行的路则输出-1。
样例输入
5 6 1 0 0 1 0 1 1 1 1 1 1 1 0 0 1 1 1 0 1 1 1 1 1 0 1 1 1 0 1 1 1 1 5 6
样例输出
(1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(2,4)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,4)->(4,4)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(2,4)->(2,5)->(3,5)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(3,4)->(3,5)->(4,5)->(5,5)->(5,6) (1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(4,3)->(4,4)->(4,5)->(5,5)->(5,6)
提示
【算法分析】
用一个a数组来存放迷宫可走的情况,另外用一个数组b来存放哪些点走过了。每个点用两个数字来描述,一个表示行号,另一个表示列号。对于某一个点(x,y),四个可能走的方向的点描述如下表:
2
1 x,y 3
4
对应的位置为:(x, y-1),(x-1, y),(x, y+1),(x+1, y)。所以每个点都要试探四个方向,如果没有走过(数组b相应的点的值为0)且可以走(数组a相应点的值为1)同时不越界,就走过去,再看有没有到达终点,到了终点则输出所走的路,否则继续走下去。
这个查找过程用search来描述如下:
procedure search(x, y, b, p);{x,y表示某一个点,b是已经过的点的情况,p是已走过的路}
begin
for i:=1 to 4 do{分别对4个点进行试探}
begin
先记住当前点的位置,已走过的情况和走过的路;
如果第i个点(xl,y1)可以走,则走过去;
如果已达终点,则输出所走的路径并置有路可走的信息,
否则继续从新的点往下查找search(xl,y1,b1,p1);
end;
end;
有些情况很明显是无解的,如从起点到终点的矩形中有一行或一列都是为0的,明显道路不通,对于这种情况要很快地“剪掉”多余分枝得出结论,这就是搜索里所说的“剪枝”。从起点开始往下的一层层的结点,看起来如同树枝一样,对于其中的“枯枝”——明显无用的节点可以先行“剪掉”,从而提高搜索速度。
代码
#include<iostream>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int N=15;
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
int n,vis[N][N],cnt,c,r,cc,rr,f=0,m;
int a[N][N];
struct node{
int x,y;
}p[250];
void dfs(int x,int y,int step){
vis[x][y]=1;
p[step].x=x;
p[step].y=y;
if(x==cc&&y==rr){
f=1;
vis[x][y]=0;
printf("(%d,%d)",c,r);
for(int i=2;i<=step;i++){
printf("->(%d,%d)",p[i].x,p[i].y);
}
cout<<endl;
return ;
}
for(int i=0;i<4;i++){
int nx=x+dx[i];
int ny=y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&vis[nx][ny]==0&&a[nx][ny]==1){
dfs(nx,ny,step+1);
vis[nx][ny]=0;
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
cin>>c>>r>>cc>>rr;
dfs(c,r,1);
if(f==0){
cout<<-1;
}
return 0;
}
蚂蚁移动问题
题目描述
桌子上有一个m行n列的方格矩阵,将每个方格用坐标表示,行坐标从下到上依次递增,列坐标从左至右依次递增,左下角方格的坐标为(1,1),则右上角方格的坐标为(m,n)。
小明是个调皮的孩子,一天他捉来一只蚂蚁,不小心把蚂蚁的右脚弄伤了,于是蚂蚁只能向上或向右移动。小明把这只蚂蚁放在左下角的方格中,蚂蚁从左下角的方格中移动到右上角的方格中,每步移动一个方格。蚂蚁始终在方格矩阵内移动,请计算出不同的移动路线的数目。
对于1行1列的方格矩阵,蚂蚁原地移动,移动路线数为1;对于1行2列(或2行1列)的方格矩阵,蚂蚁只需一次向右(或向上)移动,移动路线数也为1……对于一个2行3列的方格矩阵,如下图所示:
蚂蚁一共有3种移动路线:
路线1:(1,1) - (1,2) - (1,3) - (2,3)
路线2:(1,1) - (1,2) - (2,2) - (2,3)
路线3:(1,1) - (2,1) - (2,2) - (2,3)
输入描述
输入只有一行,包括两个整数m和n(0 < m+n ≤ 20),代表方格矩阵的行数和列数,m、n之间用空格隔开。
输出描述
输出若干行,每行一个移动路线,输出形式如样例所示。
(为保证输出一致,蚂蚁移动时先向右,再向上)
样例输入
2 3
样例输出
蚂蚁共有3种移动路线: 路线1:(1,1) - (1,2) - (1,3) - (2,3) 路线2:(1,1) - (1,2) - (2,2) - (2,3) 路线3:(1,1) - (2,1) - (2,2) - (2,3)
代码
#include<iostream>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int N=25;
int dx[2]={0,1};
int dy[2]={1,0};
int n,vis[N][N],cnt,m;
int a[N][N];
struct node{
int x,y;
}p[25],ans[500][25];
void dfs(int x,int y,int step){
vis[x][y]=1;
p[step].x=x;
p[step].y=y;
if(x==n&&y==m){
vis[x][y]=0;
cnt+=1;
for(int i=2;i<=step;i++){
ans[cnt][i]=p[i];
}
return ;
}
for(int i=0;i<2;i++){
int nx=x+dx[i];
int ny=y+dy[i];
if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&vis[nx][ny]==0){
dfs(nx,ny,step+1);
vis[nx][ny]=0;
}
}
}
int main(){
cin>>n>>m;
dfs(1,1,1);
printf("蚂蚁共有%d种移动路线:\n",cnt);
for(int i=1;i<=cnt;i++){
printf("路线%d:(1,1)",i);
for(int j=2;j<=n+m-1;j++){
printf(" - (%d,%d)",ans[i][j].x,ans[i][j].y);
}
printf("\n");
}
return 0;
}