Vjudge
A - Catch That Cow
John和奶牛分别在数轴的n和k上,john去找奶牛且奶牛不会动
john有三种移动的方式
1.向前一格
2.向后一格
3.从点x移动到点2*x
求john到奶牛的位置最少需要几步
对于n>k的情况,John只能一步步往后退去找牛,所以步数为n-k
对于n==k的情况,John不用动,这种情况可以和第一种情况合并
对于n<k的情况,通过bfs去搜索最少需要几步
#include<iostream>
#include<queue>
using namespace std;
const int N=1e5+5;
int n,k;
int vis[N]; //标记是否走过该点
int step[N]; //记录步数
bool check(int x){ //判断这个点是否在范围内
if(x>=0 && x<=1e5 )
return true;
return false;
}
int bfs(){
queue <int> q;
int start,next;
step[n]=0;//在n点的时候步数为0
q.push(n);
vis[n]=1;//标记n点走过
while(!q.empty()){
start = q.front();
if(start==k){ // 到达牛的位置 退出
return step[start];
}
q.pop();//记得取出后删除
for(int i=0;i<3;i++){ //三种走法
if(i==0){//第一种走法,向前一格
next=start+1;
}
if(i==1){//第二种走法,向后一格
next=start-1;
}
if(i==2){//第三种走法,从x移到2*x
next=start*2;
}
if(check(next) && vis[next]==0){//判断在范围内且没有走过
q.push(next);
step[next]=step[start]+1; //步骤+1
vis[next]=1;//标记走过
}
}
}
return -1;
}
int main(){
cin >> n >> k;
if(n>=k){ //这种情况下只能一步步后退
cout <<n-k << endl;
}
else{
cout<<bfs()<<endl;
}
return 0;
}
B - Find The Multiple
给一个n,要求求出一个由0和1构成的数字,使得n能被这个数整除
如果给定n有多个解,其中任何一个都是可以接受的。
从1 开始,在后面依次添加0或者1,即x -> x*10
或x -> x*10+1
当找到一个数能够整除n时,就结束搜索
要注意的是,这题要用ll
#include<iostream>
#include<queue>
typedef long long ll;
using namespace std;
int n;
void bfs(int n){
queue<ll>q;//注意要用ll
q.push(1);
while(!q.empty()){
ll x=q.front();
q.pop();
if(x%n==0){//找到一个数能够整除n
cout << x << endl;//输出这个数
return;
}
q.push(x*10);//添加0
q.push(x*10+1);//添加1
}
}
int main(){
while(cin >> n && n){
bfs(n);
}
return 0;
}
C - Prime Path
给你t组数据
每组数据给你两个四位数,每次操作只能修改一位数字
要求每次修改后的四位数都是质数
问最少花费(也就是操作次数)几次可以将第一个四位数修改成为第二个四位数
如何修改数字呢?每次将数拆成个十百千四位
改变其中一个数字,在将这四个数字组成四位数
通过判断这个数是不是四位数,并且是不是素数来剪枝
如何判断其是否为素数?埃氏筛
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
const int N=1e4+5;
int n,m;
int vis[N];
int prime[N];//素数表
struct node{
int x;//四位数的值
int cnt;//当前四位数所用的花费
};
void isprime(){
memset(prime,0,sizeof(prime)); // 初始化每一个都是素数
prime[0]=1;//不是素数
prime[1]=1;//不是素数
for(int i=2;i<N;i++){ // 埃氏筛法判断素数
if(!prime[i]){
for(int j=2*i;j<N;j=j+i){
prime[j]=1; //不是素数
}
}
}
}
int check(int x){//判断是否是四位数并且是素数
if(!prime[x] && x>=1000 && x<=9999){
return 1;
}
else
return 0;
}
void bfs()
{
node st,next;
queue<node>q;
st.x=n;
st.cnt=0;//初始花费为0
vis[st.x]=1;//标记这个数字已经出现
q.push(st);
int a[4];//用来存四位数
while(!q.empty()){
st=q.front();
q.pop();
a[0]=st.x%10;//个位
a[1]=st.x/10%10;//十位
a[2]=st.x/100%10;//百位
a[3]=st.x/1000%10; //千位
for(int i=0;i<4;i++){//对每一个数字进行改变
int temp=a[i];//标记用于回溯
for(int j=0;j<=9;j++){//数字可以是0~9
if(a[i]!=j){
a[i]=j;
next.x=a[3]*1000+a[2]*100+a[1]*10+a[0]; // 新的数字
if(next.x==m){ //与m相等,输出答案结束循环
cout << st.cnt+1 << endl;//输出花费,也就是最少操作数
return ;
}
if(check(next.x) && !vis[next.x]){ //判断合法
next.cnt=st.cnt+1;//花费增加
vis[next.x]=1;//标记已经出现
q.push(next);
}
}
}
a[i]=temp; // 回溯
}
}
cout << "Impossible" << endl;//无法修改成为目标四位数
return;
}
int main()
{
int t;
cin>>t;
isprime();//埃氏筛打表
while(t--){
memset(vis,0,sizeof(vis));//初始化
cin>>n>>m;
if(n==m){//输入的时候两个数就是相等的
cout << 0 << endl;
}
else
bfs();
}
return 0;
}
D - Pots
有两杯水,容量分别为a,b
你可以进行三种操作
1.FILL(i) 装满水
2.DROP(i) 水全部倒掉
3.POUR(i,j) i中的水倒入j
通过最少的操作次数,使得一个罐子里恰好有c升水
同时要输出操作方法
根据题意,可以知道一共有六种操作:
FILL(1) FILL(2) DROP(1) DROP(2) POUR(1,2) POUR(2,1)
要注意的是要在结构体中开一个数组用来记录操作
#include<iostream>
#include<queue>
using namespace std;
const int N=105;
int a,b,c;
bool vis[N][N];
string path[] = {"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};//六种操作
struct node {
int a, b;//两个水杯中的水的多少
int path[N];//存储路径
int step;//操作步数
};
void pr(int step,int p[]){//输出
cout << step << endl;//输出操作数
for(int i=0; i<step; i++)
cout << path[p[i]] << endl;//输出每一步的操作
}
void bfs(){
queue<node> q;
node st;
st.a=0;//a水杯初始没有水
st.b=0;//b水杯初始没有水
st.step=0;//输出操作数为0
q.push(st);
vis[st.a][st.b] = 1;//标记这种情况已经出现
while(!q.empty()) {
st = q.front();
q.pop();
if(st.a==c||st.b==c) {//两杯水中其中一杯水为c
pr(st.step, st.path);//输出操作方法
return;
}
node next;
next = st;
next.step++;//操作数+1
// FILL(a)
if(a-st.a>0) {//当前a水杯未满
next.a = a;
next.b = st.b;
if(!vis[next.a][next.b]) {
next.path[st.step] = 0;//记录路径
q.push(next);
vis[next.a][next.b]=1;
}
}
// FILL(b)
if(b - st.b > 0) {//当前b水杯未满
next.a = st.a;
next.b = b;
if(!vis[next.a][next.b]) {
next.path[st.step] = 1;
q.push(next);
vis[next.a][next.b]=1;
}
}
// DROP(a)
if(st.a) {//a水杯有水
next.a = 0;
next.b = st.b;
if(!vis[next.a][next.b]) {
next.path[st.step] = 2;
q.push(next);
vis[next.a][next.b]=1;
}
}
// DROP(b)
if(st.b) {//b水杯有水
next.a = st.a;
next.b = 0;
if(!vis[next.a][next.b]) {
next.path[st.step] = 3;
q.push(next);
vis[next.a][next.b]=1;
}
}
// POUR(a,b)
if(st.a && (st.b < b)) {//a水杯有水并且b水杯未满
if(st.a > (b - st.b)) {//倒完以后a水杯还有剩余的水,b水杯装满
next.a = st.a -(b - st.b);
next.b = b;
}
else {//a水杯的所有水都倒入b
next.a = 0;
next.b = st.b + st.a;
}
if(!vis[next.a][next.b]) {
next.path[st.step] = 4;
q.push(next);
vis[next.a][next.b]=1;
}
}
// POUR(b,a)
//和上一操作同理,只是a,b互换
if(st.b && (st.a < a)) {
if(st.b > (a - st.a)) {
next.a = a;
next.b = st.b -(a - st.a);
}
else {
next.a = st.a + st.b;
next.b = 0;
}
if(!vis[next.a][next.b]) {
next.path[st.step] = 5;
q.push(next);
vis[next.a][next.b]=1;
}
}
}
cout << "impossible" << endl;//所有情况都搜索完,还是没有找到目标情况,输出不可能
return;
}
int main()
{
cin >> a >> b >> c;
bfs();
return 0;
}
E - Asteroids!
给出一个n*n*n
的三维立体
每次输入一层
给出两个点(x,y,z),
求出从初始点到目标点的最短路径
只能走O但不能走X
如果无法到达输出"NO ROUTE"
与之前的题目不同的是,这一题要把二维数组开到三位数组
要注意给出的两点的x,y,z的坐标顺序,读清楚题
输出的是n和步数
#include<iostream>
#include<queue>
using namespace std;
const int N=15;
int n,x1,y1,z1,x2,y2,z2;
char mp[N][N][N];
int vis[N][N][N];//标记点是否出现
int dirx[6]={1,0,0,-1,0,0};//x方向
int diry[6]={0,1,0,0,-1,0};//y方向
int dirz[6]={0,0,1,0,0,-1};//z方向
struct node{
int x,y,z;//坐标
int step;//步数
};
bool check(int x,int y,int z){
if(x>=0&&x<n&&y>=0&&y<n&&z>=0&&z<n){
return true;
}
return false;
}
void bfs(){
node st,next;
queue<node>q;
st.x=x1;
st.y=y1;
st.z=z1;
st.step=0;
q.push(st);
vis[st.x][st.y][st.z]=1;
if(st.x==x2&&st.y==y2&&st.z==z2){
cout << n << " " << st.step << endl;
return;
}
while(!q.empty()){
st=q.front();
q.pop();
for(int i=0;i<6;i++){
next.x=st.x+dirx[i];
next.y=st.y+diry[i];
next.z=st.z+dirz[i];
next.step=st.step+1;//步数+1
if(next.x==x2&&next.y==y2&&next.z==z2){//到达目标点
cout << n << " " << next.step << endl;
return;
}
if(check(next.x,next.y,next.z)&&!vis[next.x][next.y][next.z]&&mp[next.x][next.y][next.z]=='O'){
vis[next.x][next.y][next.z]=1;
q.push(next);
}
}
}
cout << "NO ROUTE" << endl;
return;
}
int main()
{
string s,t;
while(cin >> s >> n){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
for(int k=0;k<n;k++){
cin >> mp[i][j][k];//三维立方体
}
}
}
cin >> y1 >> z1 >> x1 >> y2 >> z2 >> x2 >> t;//输入起始点和目标点,别忘了最后有个END要输入
bfs();
}
return 0;
}
F - Friend Chains
给出n个人的名字和m对关系
求关系最远的一对的朋友链是多少
例如x和y是朋友,y和z是朋友,x和z没有关系的话,x和z之间的朋友链即为2
用vector存每个人的朋友有哪些
由于给出的是人的名字
为了方便,可以用map来存名字和数字的对应关系,将名字转化成数字
对于每一个人的朋友进行搜索,找到朋友链最长的记录下来
要注意的是一个朋友链可以连接任意2个人,它不超过7个人。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
vector<int>ve[N];//存第i个人的朋友有哪些
int vis[N];//记录点是否被记录过
int ans;//最终答案
int flag;//标记是否有答案
void bfs(int x){
queue<int>q;
memset(vis,-1,sizeof(vis));//每次搜索的时候都要初始化,所有的点都没有经过
q.push(x);//将初始点放入
vis[x]=0;//初始点的路径为0
while(!q.empty()){//只要是非空,就说明还有路可以走
int now=q.front();
q.pop();//记得删除
if(vis[now]>ans){//有了更优的解
ans=vis[now];
if(ans>7){//只有小于等于6,才符合
flag=0;
return;
}
}
for(int i=0;i<ve[now].size();i++){//对当前搜索的点能够到达的点进行遍历
if(vis[ve[now][i]]==-1){//还没有遍历过
vis[ve[now][i]]=vis[now]+1;//路径长+1
q.push(ve[now][i]);//将这个点存入
}
}
}
return;
}
int main()
{
int n;
while(cin >> n && n){
map<string,int>mp;//用来存名字和数字的对应关系,将名字转化成数字
for(int i=1;i<=n;i++){
string s;
cin >> s;
mp[s]=i;
}
int m;
cin >> m;
memset(ve,0,sizeof(ve));//初始化,人与人之间都不是朋友
while(m--){
string x,y;
cin >> x >> y;
//相互是朋友
ve[mp[x]].push_back(mp[y]);
ve[mp[y]].push_back(mp[x]);
}
flag=1;//初始是有答案的
ans=0;//初始答案为0
for(int i=1;i<=n;i++){//对于每个人进行搜索
bfs(i);
}
if(flag){
cout << ans << endl;
}
else{
cout << -1 << endl;
}
}
}
G - Eight
给出八数码的初始状态,要求输出移动路径,使得最终变成状态12345678空
利用康托值对状态进行判重,回溯输出移动方向
#include<iostream>
#include<queue>
#include<map>
#include<cstdlib>
using namespace std;
const int MAXN=1e6+5;
char op[4]={'u','d','l','r'};//输出的移动方向
int dir[4][2]={{-1,0},{1,0},{0,-1},{0,1}};// 四个方向
int fac[9]={ 1, 1, 2, 6, 24, 120, 720, 5040, 40320};//0! 1! 2! 3!...
int vis[MAXN];//标记当前康托值所对应的状态是否出现过
int flag;//标记是否有解决方法
int idx;//x的初始位置
char path[MAXN];//记录路径
int pre[MAXN];//记录上一步的康托值
struct node{
int s[9];//状态数组
int c;//当前状态的康托值
int loc;//x的位置
};
int cantor(int s[]){//计算康托值
int ans=1;//注意,因为 12345..是算作0开始计算的,最后结果要把12345..看作是第一个
for(int i=0;i<9;i++){
int tmp=0;//用来计数
for(int j=i+1;j<9;j++){
if(s[i]>s[j]) tmp++;计算s[i]是第几大的数,或者说计算有几个比他小的数
}
ans=ans+tmp*fac[9-i-1];
}
return ans;
}
bool check(int x,int y){//判断是否在3*3的矩阵坐标内
if(x>=0 && x<=2 && y>=0 && y<=2){
return 1;
}
return 0;
}
void bfs(node start){
queue<node>q;
node next;
vis[start.c]=1;//记录开始状态出现过
pre[start.c]=-1;//开始状态的上一个状态为-1,用于输出路径
q.push(start);//入队
while(!q.empty()){
start=q.front();//取第一个
q.pop();//取出就删除
if(start.c==1){//如果找到了最终状态123456789,也就是康托值为1
flag=1;//标记有解决方法
return;//结束搜索
}
int x=start.loc/3;//x的位置/3即为在3*3矩阵中的x
int y=start.loc%3;//x的位置%3即为在3*3矩阵中的y
for(int i=0;i<4;i++){//四种方向
int nowx=x+dir[i][0];//x改变
int nowy=y+dir[i][1];//y改变
if(check(nowx,nowy)){//判断是否合法
next=start;
swap(next.s[nowx*3+nowy],next.s[x*3+y]);//将空格也就是9与移动的那一个数字进行交换位置
next.c=cantor(next.s);//修改康托值
if(!vis[next.c]){//判断这个康托值对应的状态是否出现过
vis[next.c]=1;//标记出现过此种状态
next.loc=nowx*3+nowy;//移动后状态的x的位置
pre[next.c]=start.c;//记录(当前康托值的状态)的(上一步的状态)的康托值
path[next.c]=op[i];//记录得到(当前康托值得状态)的移动方向(包括'u','d','l','r')
q.push(next);//将新得到的状态入队
}
}
}
}
return;
}
void pr(int x){//回溯输出移动方向
if(pre[x]==-1){//当这个状态的上一个状态是-1,说明已经到了初始状态
return;
}
pr(pre[x]);//查找上一步
cout << path[x];//输出移动方向
}
int main()
{
ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
string str;
int cnt=0;
node st;//记录初始状态
for(int i=0;i<9;i++){
cin >> str;//输入起始状态
if(str=="x"){
idx=i;//记下x在起始状态中的位置
st.s[cnt++]=9;//起始状态数组
}
else st.s[cnt++]=atoi(str.c_str());//将字符串转为数字
}
st.loc=idx;//x的位置
st.c=cantor(st.s);//康托值
flag=0;//初始标记无解决方法
bfs(st);//广搜
if(!flag){//无解决方法
cout << "unsolvable" << endl;
}
else{//有解决方法
pr(1);//回溯输出移动方向
cout << endl;
}
return 0;
}
wlcam
问题 A: Red and Black
#include<iostream>
#include<queue>// 队列
using namespace std;
const int N=20+5;// 房间大小范围
char mp[N][N];// 房间地砖
int dir[4][2]={{-1,0},{0,-1},{1,0},{0,1}};// 四个方向
int num;// 所能到达的黑色瓷砖的数量
int n,m;// 房间的长和宽
struct node{// 记录瓷砖的坐标
int x;
int y;
};
bool check(int x,int y){// 判断点坐标是否合法
if(x>=1 && x<=n && y>=1 && y<=m){// 在整个房间的大小范围内即为合法
return 1;
}
else{
return 0;
}
}
void bfs(int dx,int dy){
queue<node>q;// 存结构体的队列
node start,next;
start.x=dx;
start.y=dy;
q.push(start);// 起点以结构体的形式进入队列
num++;// 起始点也为黑砖
while(!q.empty()){// 队列非空
start=q.front();// 取出队列第一个元素
q.pop();// 取出的同时还要记得删除队列第一个元素
for(int i=0;i<4;i++){// 有四个方向
next.x=start.x+dir[i][0];
next.y=start.y+dir[i][1];
//此时next存的是走了一步之后到达的坐标,也就是扩散的点,判断其是否符合条件
// check用来判断这个坐标是否合法,同时要判断这个点是否是黑砖
if(check(next.x,next.y) && mp[next.x][next.y]=='.'){
//这个地砖可以到达
mp[next.x][next.y]='#';// 将这个地砖变为#,标记这个地砖已经踩过了
num++;// 能够到达的黑砖+1
q.push(next);// 将符合条件的扩散的点存入队列,用于之后进行扩散
}
}
}
}
int main()
{
int stx,sty;
while(cin >> m >> n && n && m){// 多组样例输入 且 当n和m为0时结束
num=0;// 初始化
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin >> mp[i][j];
if(mp[i][j]=='@'){// 记下起始点的坐标
stx=i;
sty=j;
}
}
}
bfs(stx,sty);// 广搜
cout << num << endl;// 输出能够到达的黑砖的数量
}
return 0;
}
问题 B: 细胞有几个
给你一个矩阵,非零的数字代表细胞
如果数字的上下左右还是细胞,则为同一细胞
问有几个细胞
这题也就是问你有几个连通块
可以对每一个非0的细胞的四周进行搜索
如果还是细胞就入队,直到没有连通的细胞了,说明这一片就是一个细胞
注意搜索过的细胞要标记
此处可以将搜索过的细胞的数字标记为0
注意每次读入一位数字可以这样读入scanf("%1d",&a[i][j]);//每次输入一个数
#include<iostream>
#include<stdio.h>
#include<queue>
using namespace std;
const int N=75;
int n,m;
int dir[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
int a[N][N];
int ans;
struct node{
int x,y;
};
void bfs(int dx,int dy){
node st;
queue<node>q;
st.x=dx;
st.y=dy;
a[st.x][st.y]=0;
q.push(st);
while(!q.empty()){
node now=q.front();
q.pop();
for(int i=0;i<4;i++){//四个方向
node next;
int nx=now.x+dir[i][0];
int ny=now.y+dir[i][1];
if(nx>=0 && ny>=0 && nx<m && ny<n && a[nx][ny]!=0){//没有被标记过并且也是细胞
a[nx][ny]=0;//标记搜索到了
next.x=nx;
next.y=ny;
q.push(next);
}
}
}
ans++;//这些搜索到的细胞为一个连通块
}
int main()
{
cin>>m>>n;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
scanf("%1d",&a[i][j]);//每次输入一个数
}
}
ans=0;
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
if(a[i][j]!=0){//是细胞
bfs(i,j);//从这个细胞开始向四周搜索
}
}
}
cout << ans << endl;
return 0;
}
问题 C: 面积
计算*围成的0的个数
这题可以把没被包围的地方改成1,这样只需要计算0剩下的个数就好了
从(1,1)点开始搜索,如果附近四个方向中有0的话,就从这个0点继续往下扩散
如果遇到1,就停止,这样能够保证1包围的0一定不会被修改成1
#include<bits/stdc++.h>
using namespace std;
const int N=15;
int a[N][N];
int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
struct node{
int x;
int y;
};
void bfs(){//把没被包围的地方全部改成1
queue<node>q;
node start;
start.x=1;
start.y=1;
q.push(start);
a[1][1]=1;
while(!q.empty()){
node now=q.front();
q.pop();
for(int i=0;i<4;i++){
node next;
next.x=now.x+dir[i][0];
next.y=now.y+dir[i][1];
if(a[next.x][next.y]==0&&next.x<=11&&next.x>=0&&next.y>=0&&next.y<=11){
a[next.x][next.y]=1;
q.push(next);
}
}
}
}
int main(){
for(int i=1;i<=10;i++){
for(int j=1;j<=10;j++){
cin >> a[i][j];
}
}
bfs();
int sum=0;
for(int i=1;i<=10;i++){//计算还有多少个0
for(int j=1;j<=10;j++){
if(a[i][j]==0) sum++;
}
}
//剩余的0的个数即为答案
cout << sum << endl;
return 0;
}
/**
如果像以下这种情况,0被分成了好几块
但是由于我们是从左上角开始搜索的,当他遇到1的时候,他就会停止搜索
那么右上方这一片0就不会搜索到,也就不能被修改成1
所以为了能够让这几块0连通,我们可以在整个10*10的方阵最外面添加一圈0
以保证没有被1圈住的0全部被修改成1
0 0 1 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1
56
**/
问题 D: 营救
给出一张海洋图,其中1为陆地,0为海洋,要求从起点到目标点的最短距离
读入的时候注意每次只读一个数字
#include<iostream>
#include<queue>
using namespace std;
const int N=1e3+5;
int n;
int dir[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
char a[N][N];
int vis[N][N];
int sx,sy,ex,ey;
bool check(int x,int y){
if(!a[x][y] && !vis[x][y] && x>=1 && y>=1 && x<=n && y<=n){
return true;
}
return false;
}
struct node{
int x;
int y;
int step;
};
int bfs(){
node st;
st.x=sx;
st.y=sy;
st.step=0;
queue<node>q;
q.push(st);
vis[sx][sy]=1;
while(!q.empty()){
node now=q.front();
q.pop();
for(int i=0;i<4;i++){
node next;
next.x=dir[i][0]+now.x;
next.y=dir[i][1]+now.y;
next.step=now.step+1;
if(next.x==ex && next.y==ey){
return next.step;
}
if(check(next.x,next.y)){
vis[next.x][next.y]=1;
q.push(next);
}
}
}
return -1;
}
int main()
{
cin >> n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%1d",&a[i][j]);
}
}
cin >>sx>>sy>>ex>>ey;
int ans=bfs();
cout << ans <<endl;
return 0;
}
问题 E: 最少转弯问题
给出一个矩阵,其中0表示空地,1表示高山,计算从起始点到目标点的最少转弯次数
怎么判断转弯了?每次记录上一步的方向,如果这次移动的方向和上一步的方向相同,则说明没有转弯
如果这次移动的方向和上一步的方向不同,则说明转弯了
最后要输出转弯的最小次数,需要求每次到达目标状态路径的转弯次数的最小值
#include<bits/stdc++.h>
using namespace std;
const int N=105;
int m,n;
int a[N][N];
int x2,y2;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
struct node{
int x;//坐标
int y;//坐标
int pre;//上一个方向
int cnt;//转弯次数
};
int bfs(int x,int y){
queue <node>q;
node start,now;
start.x=x;
start.y=y;
start.pre=-1;//起始点的上一步为-1
start.cnt=0;
q.push(start);
int ans=0x3f3f3f3f;//初始化无穷大
while(!q.empty()){
node now=q.front();
q.pop();
a[now.x][now.y]=1;//标记已经走过
if(now.x==x2&&now.y==y2){//目标状态
ans=min(ans,now.cnt);//取最小转弯次数
continue;
}
for(int i=0;i<4;i++){
int xx=now.x+dir[i][0];
int yy=now.y+dir[i][1];
if(xx>=1&&xx<=n&&yy>=1&&yy<=m&&a[xx][yy]!=1){
node nn;
nn.x=xx;
nn.y=yy;
if(now.pre==-1){//是第一步
nn.pre=i;
nn.cnt=0;
}
else if(now.pre!=i){//这一步的方向和上一步的方向不一样
nn.pre=i;//记录方向
nn.cnt=now.cnt+1;//转弯次数+1
}
else{
nn.pre=i;//方向相同
nn.cnt=now.cnt;//转弯次数不变
}
q.push(nn);
}
}
}
return ans;
}
int main(){
cin >>n >> m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin >> a[i][j];
}
}
int x1,y1;
cin >> x1 >> y1 >> x2 >> y2;
cout << bfs(x1,y1) << endl;
return 0;
}
问题 F: 马的移动
给出马的起始位置和目标位置,计算最短距离
注意是多组样例输入,每次都要初始化用来标记的数组
注意输出格式
#include <bits/stdc++.h>
using namespace std;
int a[10][10];
int sx,sy,ex,ey;
int dirx[8]={-1,-2,-1,-2,1,2,1,2};
int diry[8]={-2,-1,2,1,-2,-1,2,1};
struct node{
int x;
int y;
int step;
};
bool check(int x,int y){
if(x>=1 && x<=8 && y>=1 && y<=8) return true;
else return false;
}
int bfs(){
queue<node>q;
node start;
start.x=sx;
start.y=sy;
start.step=0;
q.push(start);
a[sx][sy]=1;
while(!q.empty()){
node now=q.front();
q.pop();
if(now.x==ex&&now.y==ey)//到达目标地点
return now.step;//返回步数
for(int i=0;i<8;i++){//8个方向
int nx=now.x+dirx[i];
int ny=now.y+diry[i];
if(check(nx,ny) && a[nx][ny]!=1){
a[nx][ny]=1;
node next;
next.x=nx;
next.y=ny;
next.step=now.step+1;
q.push(next);
}
}
}
}
int main(){
string s1,s2;
while(cin >> s1 >> s2){
memset(a,0,sizeof(a));
sx=s1[0]-'a'+1,sy=s1[1]-'0';
ex=s2[0]-'a'+1,ey=s2[1]-'0';
cout << "To get from " << s1 << " to " << s2 << " takes " << bfs() << " knight moves." << endl;
}
return 0;
}