Knights of Ni (bfs)

本文介绍了一个迷宫寻径问题,目标是从起点出发找到一条最短路径先获取物品再抵达终点。通过使用广度优先搜索算法,并结合状态标记,有效地解决了这一问题。

Description

Bessie is in Camelot and has encountered a sticky situation: she needs to pass through the forest that is guarded by the Knights of Ni. In order to pass through safely, the Knights have demanded that she bring them a single shrubbery. Time is of the essence, and Bessie must find and bring them a shrubbery as quickly as possible.

Bessie has a map of of the forest, which is partitioned into a square grid arrayed in the usual manner, with axes parallel to the X and Y axes. The map is W x H units in size (1 <= W <= 1000; 1 <= H <= 1000).

The map shows where Bessie starts her quest, the single square where the Knights of Ni are, and the locations of all the shrubberies of the land. It also shows which areas of the map can be traverse (some grid blocks are impassable because of swamps, cliffs, and killer rabbits). Bessie can not pass through the Knights of Ni square without a shrubbery.

In order to make sure that she follows the map correctly, Bessie can only move in four directions: North, East, South, or West (i.e., NOT diagonally). She requires one day to complete a traversal from one grid block to a neighboring grid block.

It is guaranteed that Bessie will be able to obtain a shrubbery and then deliver it to the Knights of Ni. Determine the quickest way for her to do so.

Input

Line 1: Two space-separated integers: W and H.

Lines 2..?: These lines describe the map, row by row. The first line describes the most northwest part of the map; the last line describes the most southeast part of the map. Successive integers in the input describe columns of the map from west to east. Each new row of a map's description starts on a new input line, and each input line contains no more than 40 space-separated integers. If W <= 40, then each input line describes a complete row of the map. If W > 40, then more than one line is used to describe a single row, 40 integers on each line except potentially the last one. No input line ever describes elements of more than one row.

The integers that describe the map come from this set:
0: Square through which Bessie can travel
1: Impassable square that Bessie cannot traverse
2: Bessie's starting location
3: Location of the Knights of Ni
4: Location of a shrubbery

Output

Line 1: D, the minimum number of days it will take Bessie to reach a shrubbery and bring it to the Knights of Ni.

Sample Input

8 4
4 1 0 0 0 0 1 0
0 0 0 1 0 1 0 0
0 2 1 1 3 0 4 0
0 0 0 4 1 1 1 0

Sample Output

11

Hint

Explanation of the sample:

Width=8, height=4. Bessie starts on the third row, only a few squares away from the Knights.

Bessie can move in this pattern to get a shrubbery for the Knights: N, W, N, S, E, E, N, E, E, S, S. She gets the shrubbery in the northwest corner and then makes her away around the barriers to the east and then south to the Knights.
题意:
给你一个地图从数字2开始走,然后带上4,走到数字3,问你最小能走多少步?
思路:
等走到3的时候标记一下,然后带着4,走到3. 就是开一个结构体,里面有,位置x,y,step,还有重要的一个变量叫它thing吧,如果thing为0,那就表明没有带上4,相反,带上了4这个物品。
这个方法很快写好了,但是。。。。。。一直没有出来结果。为什么呢?
刚刚看了别人的blog才发现的,那就是,要设一个标记数组,来走没走过,当时我也在疑惑啊,如果标记了那么带上东西不就走不回来了?所以找了半天的错,就是在这里。
找了一下午啊,主要还是对于标记数组没有足够的认识啊。。。
自己写的没有带标记数组的代码:


#if 0
#include<bits/stdc++.h>
using namespace std;
#define MAX 2000+50
int w,h;

int f[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; 

int a[MAX][MAX],sx,sy,ex,ey;
bool ok(int i,int j)
{
	if(i>=0&&i<h&&j>=0&&j<w)
	{
			return 1;		
	}	
	return 0;	
}

struct node
{
	int x,y,step;
	int thing;	
};


void bfs()
{
	queue<node> q;
	node now;
	now.step=0;
	now.x=sx;
	now.y=sy;
	now.thing=0;
	
	q.push(now);
	
	while(!q.empty()) 
	{
		now=q.front(); 
		q.pop();
		
		if(now.x==ex&&now.y==ey)   
		{
			if(now.thing==1)
			{
				cout<<now.step<<endl;
				return;
			}
		}
		else
		for(int i=0; i<4; i++)
		{
			node next;
			next.x=now.x+f[i][0];
			next.y=now.y+f[i][1];
			
			if(ok(next.x,next.y)) 
			{
				if(a[next.x][next.y]!=1) 
				{
					if(a[next.x][next.y]==4)
					{
						next.thing=1;
						next.step=now.step+1;
						q.push(next);	
					}
					else 
					{
						next.step=now.step+1;
						q.push(next);
					}
					
				}
			}
		}
	}
}

int main()
{
	while(cin>>w>>h)
	{
		memset(a,0,sizeof(a));
		//memset(b,0,sizeof(b));
		for(int i=0; i<h; i++)
		{
			for(int j=0; j<w; j++)
			{
				cin>>a[i][j];
				if(a[i][j]==2)
				{
					sx=i;
					sy=j;	
				}
				else if(a[i][j]==3)
				{
					ex=i;
					ey=j;
				}	
			}	
		}
		
		bfs();	
	}		
	
}

#endif



完美的代码:

///
///vis开三维判断到4之前和到4之后是否访问过该点
# include <stdio.h>
# include <algorithm>
# include <string.h>
# include <queue>
using namespace std;
int xx[4]={0,0,1,-1};
int yy[4]={1,-1,0,0};
struct node
{
    int x;
    int y;
    int step;
    int flag;
};
int n,m;
int a[1010][1010];
int vis[1010][1010][2];
void bfs(int ax,int ay)
{
    memset(vis,0,sizeof(vis));
    node front,next;
    front.x=ax;
    front.y=ay;
    front.step=0;
    front.flag=0;
    vis[ax][ay][0]=1;
    queue<node>q;
    q.push(front);
    while(!q.empty())
    {
        front=q.front();
        q.pop();
        if(a[front.x][front.y]==3&&front.flag==1)
        {
            printf("%d\n",front.step);
            return ;
        }
        for(int i=0;i<4;i++)
        {
            next.x=front.x+xx[i];
            next.y=front.y+yy[i];
            next.step=front.step+1;
            if(a[next.x][next.y]==4||front.flag==1)
                next.flag=1;
            else
                next.flag=0;
            if(next.x>=0&&next.x<n&&next.y>=0&&next.y<m&&a[next.x][next.y]!=1&&!vis[next.x][next.y][next.flag])
            {
                vis[next.x][next.y][next.flag]=1;
                q.push(next);
            }
        }
    }
    return ;
}
int main()
{
    int i,j,ax,ay;
    while(~scanf("%d%d",&m,&n))
    {
        for(i=0; i<n; i++)
        {
            for(j=0; j<m; j++)
            {
                scanf("%d",&a[i][j]);
                if(a[i][j]==2)
                {
                    ax=i;
                    ay=j;
                }
            }
        }
        bfs(ax,ay);
    }
    return 0;
}














def main(): import sys input = sys.stdin.read().split() ptr = 0 n = int(input[ptr]) ptr += 1 m = int(input[ptr]) ptr += 1 obstacles = set() for _ in range(m): x = int(input[ptr]) - 1 # 转换为 0-based 索引 ptr += 1 y = int(input[ptr]) - 1 ptr += 1 obstacles.add((x, y)) # 1. 统计可放置的总格子数 & 构建二分图 color = [[(i + j) % 2 for j in range(n)] for i in range(n)] total = 0 graph = [[] for _ in range(n * n)] # 黑格 -> 白格的邻接表 # 骑士的 8 种移动方向 dirs = [(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2), (2, -1), (2, 1)] for i in range(n): for j in range(n): if (i, j) in obstacles: continue total += 1 if color[i][j] != 0: # 只处理黑格(0-based 染色) continue # 遍历所有可能的攻击位置 for dx, dy in dirs: ni, nj = i + dx, j + dy if 0 <= ni < n and 0 <= nj < n and (ni, nj) not in obstacles: # 转换为一维索引 u = i * n + j v = ni * n + nj graph[u].append(v) # 2. 迭代版匈牙利算法(非递归,避免栈溢出) def max_matching(): match_to = [None] * (n * n) # 记录白格对应的黑格匹配(列表实现) result = 0 for u in range(n * n): # 只处理黑格且未被障碍阻挡的位置 i, j = u // n, u % n if (i, j) in obstacles or color[i][j] != 0: continue visited = [False] * (n * n) stack = [(u, iter(graph[u]))] prev = {} # 记录路径,用于回溯更新匹配 found = False v_found = None # 记录找到的白格 while stack: node, neighbors = stack[-1] try: v = next(neighbors) if not visited[v]: visited[v] = True if match_to[v] is None: found = True v_found = v break else: # 记录路径,用于后续回溯 prev[v] = node stack.append((match_to[v], iter(graph[match_to[v]]))) except StopIteration: stack.pop() # 找到增广路径,更新匹配(列表索引访问) if found: v = v_found while v is not None: u_prev = prev.get(v, None) match_to[v] = u u = u_prev # 列表按索引访问,判断 u 合法性 v = match_to[u] if u is not None and 0 <= u < len(match_to) else None result += 1 return result # 3. 计算最大独立集 matching = max_matching() max_knights = total - matching print(max_knights) if __name__ == "__main__": main()
最新发布
06-07
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值