題意
巡邏機器人從起點(1,1)到終點(m,n)。求最短路徑長度,其中機器人可以連續穿過不超過k個障礙物。
解題思路
首先要明白穿過障礙物並不代表一定要直線飛過,可以各種拐彎飛,只要不超過k個就行。求最短路自然想到了bfs,和普通的bfs不同的是訪問標誌需要更換爲到達該座標穿過障礙物的個數和普通訪問標誌。當訪問標誌位true說明前面已經到達過該座標,這時需要判斷到達該座標穿過的障礙物的個數是否小於以前的個數,如果小於便繼續加入隊列。只要注意更新穿過障礙物的個數就可以了。
ac代碼
#include <iostream>
#include <string>
#include <queue>
#include <string.h>
using namespace std;
const int maxn = 20 + 5;
const int INF = 1e9;
int d[maxn][maxn];
string mp[maxn];
int vis[maxn][maxn];
int knum[maxn][maxn];
int n, m, k;
int dirl[5] = { 1,0,-1,0 };
int dirr[5] = { 0,1,0,-1 };
struct node {
int x, y, step,k;
node(int x = 0, int y = 0, int step = 0, int k = 0) : x(x), y(y), step(step),k(k){}
node getDir(int d)
{
return node(x + dirl[d], y + dirr[d], step+1);
}
bool vaild(int maxk)
{
return x >= 0 && x < n && y >= 0 && y < m && k <= maxk;
}
bool operator < (const node b) const
{
return step > b.step;
}
void setvis()
{
vis[y][x] = 1;
}
void setStep()
{
d[y][x] = step;
}
bool judge()
{
return x >= 0 && x < n && y >= 0 && y < m && (mp[y][x] == '1') ;
}
};
void init()
{
memset(vis, 0, sizeof(vis));
memset(knum, 0, sizeof(knum));
for (int i = 0; i < maxn; i++)
for (int j = 0; j < maxn; j++)
d[i][j] = INF;
for (int i = 0; i < maxn; i++)
mp[i].resize(maxn);
}
void bfs()
{
priority_queue<node> q;
q.push(node(0, 0, 0));
vis[0][0] = 1;
d[0][0] = 0;
node temp,next;
while (!q.empty())
{
temp = q.top();q.pop();
for (int i = 0; i < 4; i++)
{
next = temp.getDir(i);
if (next.judge())
next.k = temp.k + 1;
if (next.vaild(k) && ((vis[next.y][next.x] != 1) || (vis[next.y][next.x] == 1 && next.k < knum[next.y][next.x])))
{
knum[next.y][next.x] = next.k;
next.setStep();
next.setvis();
q.push(next);
}
}
}
}
int main()
{
//freopen("cin.txt", "r", stdin);
//freopen("cout.txt", "w", stdout);
int T;
scanf("%d", &T);
while (T--)
{
init();
scanf("%d%d", &m, &n);
scanf("%d", &k);
for (int i = 0; i < m;i++)
for (int j = 0; j < n; j++)
{
cin >> mp[i][j];
}
bfs();
if (d[m - 1][n - 1] != INF)
cout << d[m - 1][n - 1]<< endl;
else cout << -1 << endl;
}
return 0;
}