220128总结
220128总结
被卡深搜的一天
-
面积(Area)
昨天原题直接复制(
-
营救(Save)
【问题描述】
铁塔尼号遇险了!他发出了求救信号。距离最近的哥伦比亚号收到了讯息,时间就是生命,必须尽快
赶到那里。
通过侦测,哥伦比亚号获取了一张海洋图。这张图将海洋部分分化成 n个比较小的单位,其中用 1
标明的是陆地,用 0 标明是海洋。船只能从一个格子,移到相邻的四个格子。
为了尽快赶到出事地点,哥伦比亚号最少需要走多远的距离。
【输入格式】
第一行为 n,下面是一个 n 的 0、1 矩阵,表示海洋地图
最后一行为四个小于 n 的整数,分别表示哥伦比亚号和铁塔尼号的位置。
【输出格式】
哥伦比亚号到铁塔尼号的最短距离,答案精确到整数。
【输入样例】
3
001
101
100
1 1 3 3
【输出样例】
4
【数据范围】
N<=1000广搜最先到达的就是最短的路径
void BFS(){ queue<pair<int,int> > A; A.push(make_pair(frx,fry)); queue<int>steps; steps.push(1); while(!A.empty()){ int ns = 0; for(int i = 0;i<4;i++){ int xx = A.front().first + F[i][0]; int yy = A.front().second + F[i][1]; step += 1; if(xx > n || xx < 1) continue; if(yy > n || yy < 1) continue; if(map_[xx][yy] == 1) continue; if(xx == tox && yy == toy) printf("%d",steps.front()); A.push(make_pair(xx,yy)); steps.push(steps.front()+1); map_[xx][yy] = 1; } A.pop(); steps.pop(); } }
-
最少转弯问题(turn)
【问题描述】
给出一张地图,这张地图被分为\(n\times m(n,m\leqslant 100)\)个方块,任何一个方块不是平地就是高山。平地可以通过,高山则不能。现在你处在地图的\((x_1,y_1)\)这块平地,问:你至少需要拐几个弯才能到达目的地\((x_2,y_2)\)?你只能沿着水平和垂直方向的平地上行进,拐弯次数就等于行进方向的改变(从水平到垂直或从垂直到水平)的次数。例如:如图,最少的拐弯次数为5。
【输入格式】
第一行:n和m。
第二至n+1行:一个矩阵,为地图。(0:空地;1:高山。)
第n+2行:x1,y1,x2和y2。【输出格式】
只有一行,为最少的转弯次数。
【样例输入】
5 7
1 0 0 0 0 1 0
0 0 1 0 1 0 0
0 0 0 0 1 0 1
0 1 1 0 0 0 0
0 0 0 0 1 1 0
1 3 1 7【样例输出】
5
这题我写得不太严谨
(可是996上的数据真的很水,没有考虑两次到达同一点的情况宽搜时最先到达一个点时一定是最短路径但不一定是最少转弯
正解可以参考T4
-
在一种"麻将"游戏中,游戏是在一个有 w*h 格子的矩形平板上进行的。每个格子可以放
置一个麻将牌,也可以不放(如图所示)。玩家的目标是将平板上的所有可通过一条路径相
连的两张相同的麻将牌,从平板上移去。最后如果能将所有牌移出平板,则算过关。
这个游戏中的一个关键问题是:两张牌之间是否可以被一条路径所连接,该路径满足以
下两个特性:-
它由若干条线段组成,每条线段要么是水平方向,要么是垂直方向。
-
这条路径不能横穿任何一个麻将牌 (但允许路径暂时离开平板)。
这是一个例子。
在(1,3)的牌和在(4, 4)的牌可以被连接。(2, 3)和(3, 4)不能被连接。
你的任务是编一个程序,检测两张牌是否能被一条符合以上规定的路径所连接。
【输入格式】
第一行有两个整数\(w,h(1\leqslant w,h\leqslant 75)\),表示平板的宽和高。接下来
h
行描述平板信息,每行包含w
个字符,如果某格子有一张牌,则这个格子上有个'X',否则是一个空格。平板上最左上角格子的坐标为\((1,1)\),最右下角格子的坐标为\((w,h)\)。接下来的若干行,每行有四个数\(x1,y1,x2,y2\) ,且满足\(1\leqslant x1,x2 \leqslant w\)\(1\leqslant y1,y2\leqslant h\),表示两张牌的坐标(这两张牌的坐标总是不同的)。如果出现连续四个0,则表示输入结束。【样例输入】(0代表空格)
5 4
XXXXX
X000X
XXX0X
0XXX0
2 3 5 3
1 3 4 4
2 3 3 4
0 0 0 0
【样例输出】
4
3
0这真的不是连连看吗基本思路就是宽搜
不过需要尽可能多地走直线,因为要求的是最小转弯数
那么就按一个方向一直走下去,直到出范围或者遇上其他麻将
如果遇上的一个位置是曾经走到过的位置
#include<bits/stdc++.h> using namespace std; int map_[100][100]; int F[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; int w,h; struct node{ int x,y; int depth; }; int BFS(int stx,int sty,int tox,int toy){ queue<node> A; int canGo[100][100]; memset(canGo,0,sizeof(canGo)); node a; a.x = stx; a.y = sty; a.depth = 0; A.push(a); while(!A.empty()){ a = A.front(); A.pop(); for(int i = 0;i<4;++i){ int tx = a.x + F[i][0]; int ty = a.y + F[i][1]; //四个方向都走到头 while(true){ //出框了就停 if(tx < 1 || tx > h+2) break; if(ty < 1 || ty > w+2) break; //这个点曾经到达过且这个点深度比当前大1(即下一步会走到且两次走到该点的步数相同)就停 if(!(canGo[tx][ty] == 0 || canGo[tx][ty] == a.depth +1)) break; //到达目标点就返回值 if(tx == tox && ty == toy) return a.depth+1; //如果该点为不可走就停止 //这句和上句判断到达目标点不可调序,因为目标点不可走 if(map_[tx][ty] == -1) break; //在地图上留下到达该点所耗步数 canGo[tx][ty] = a.depth+1; //将这个点入队 node b; b.x = tx; b.y = ty; b.depth = a.depth+1; A.push(b); tx += F[i][0]; ty += F[i][1]; } } } return 0; } int main(){ scanf("%d%d",&w,&h); memset(map_,-1,sizeof(map_)); for(int i = 1;i<h+3;i++){ map_[i][1] = 0; map_[i][w+2] = 0; } for(int i = 1;i<w+3;i++){ map_[1][i] = 0; map_[h+2][i] = 0; } getchar(); for(int i = 2;i<h+2;i++){ for(int j = 2;j<w+2;j++){ char c; c = getchar(); map_[i][j] = (c == 'X')?-1:0; } getchar(); } while(true){ int x,y,xx,yy; scanf("%d%d%d%d",&y,&x,&yy,&xx); if(x == 0 && y == 0 && xx == 0 && yy == 0) break; int ds = BFS(x+1,y+1,xx+1,yy+1); printf("%d\n",ds); } return 0; } //5 4 //XXXXX //X X //XXX X // XXX //2 3 5 3 //1 3 4 4 //2 3 3 4 //0 0 0 0
-