思路:对于每个药物点,跑一遍bfs,看他在不吃任何其他药的情况下能达到哪些其他药物点。这就连成了一个图论网络,最后从起始点再来一次bfs,判断从起始点能否通过这个图论网络到达终点。
时间复杂度 Θ(nm2),但是为什么T了一堆而且被教练制裁呢?
代码:
#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cctype>
#include <bitset>
#pragma GCC optimize("O3","Ofast","unroll-loops")
using namespace std;
const int N = 305,M = 205;
int h,w,n,begx,begy,endx,endy,tmp2;
char cc;
//type:1=通路,0=障碍物
bool a[M][M];
//把药物点标记出来
int mp[M][M];
int r[N],c[N],e[N];
//表示每个药物点可以到哪些其他药物点,如果可以到终点就存一个n+1
vector<int> v[N];
struct point
{
int x;
int y;
int energy;
} tmp;
bool visited[M][M];
bitset<N> visited2;
namespace tallnut{void qread(int&x){char c=getchar();bool flag=false;while((!isdigit(c))&&(c!='-'))c=getchar();if(c=='-'){flag=true;c=getchar();}x=0;while(isdigit(c)){x=(x<<3)+(x<<1)+c-'0';c=getchar();}if(flag)x=-x;}void qread(unsigned&x){char c=getchar();while(!isdigit(c))c=getchar();x=0;while(isdigit(c)){x=(x<<3)+(x<<1)+c-'0';c=getchar();}}void qread(long long&x){char c=getchar();bool flag=false;while((!isdigit(c))&&(c!='-'))c=getchar();if(c=='-'){flag=true;c=getchar();}x=0;while(isdigit(c)){x=(x<<3)+(x<<1)+c-'0';c=getchar();}if(flag)x=-x;}void qread(unsigned long long&x){char c=getchar();while(!isdigit(c))c=getchar();x=0;while(isdigit(c)){x=(x<<3)+(x<<1)+c-'0';c=getchar();}}void qwrite(int x){if(x==0){putchar('0');return;}if(x<0){putchar('-');x=-x;}int stack[11];int cnt=0;while(x){stack[++cnt]=x%10;x/=10;}while(cnt)putchar(stack[cnt--]+'0');}void qwrite(unsigned x){if(x==0){putchar('0');return;}int stack[11];int cnt=0;while(x){stack[++cnt]=x%10;x/=10;}while(cnt)putchar(stack[cnt--]+'0');}void qwrite(long long x){if(x==0){putchar('0');return;}if(x<0){putchar('-');x=-x;}int stack[20];int cnt=0;while(x){stack[++cnt]=x%10;x/=10;}while(cnt)putchar(stack[cnt--]+'0');}void qwrite(unsigned long long x){if(x==0){putchar('0');return;}int stack[20];int cnt=0;while(x){stack[++cnt]=x%10;x/=10;}while(cnt)putchar(stack[cnt--]+'0');}}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
tallnut::qread(h);
tallnut::qread(w);
for (int i = 1;i <= h;i++)
{
for (int j = 1;j <= w;j++)
{
cc = getchar();
switch (cc)
{
case '.':
a[i][j] = true;
break;
case '#':
a[i][j] = false;
break;
case 'S':
a[i][j] = true;
begx = i;
begy = j;
break;
case 'T':
a[i][j] = true;
endx = i;
endy = j;
break;
}
}
cc = getchar();
}
tallnut::qread(n);
for (int i = 1;i <= n;i++)
{
tallnut::qread(r[i]);
tallnut::qread(c[i]);
tallnut::qread(e[i]);
mp[r[i]][c[i]] = i;
}
//如果起始点没有药物:直接拉倒
if (mp[begx][begy] == 0)
{
puts("No");
return 0;
}
//以每个药物点为中心,向外延展,看看能到哪里
for (int i = 1;i <= n;i++)
{
//广搜
queue<point> q;
q.push({r[i],c[i],e[i]});
while (q.size())
{
tmp = q.front();
q.pop();
//看看是不是其他药物点
if (mp[tmp.x][tmp.y] > 0) v[i].push_back(mp[tmp.x][tmp.y]);
//看看是不是终点
if (tmp.x == endx && tmp.y == endy) v[i].push_back(n + 1);
//打标记
visited[tmp.x][tmp.y] = true;
//如果体力不够就拉倒
if (tmp.energy == 0) continue;
//向外扩展
//上
if (tmp.x > 1 && a[tmp.x - 1][tmp.y] && (!visited[tmp.x - 1][tmp.y]))
q.push({tmp.x - 1,tmp.y,tmp.energy - 1});
//下
if (tmp.x < h && a[tmp.x + 1][tmp.y] && (!visited[tmp.x + 1][tmp.y]))
q.push({tmp.x + 1,tmp.y,tmp.energy - 1});
//左
if (tmp.y > 1 && a[tmp.x][tmp.y - 1] && (!visited[tmp.x][tmp.y - 1]))
q.push({tmp.x,tmp.y - 1,tmp.energy - 1});
//右
if (tmp.y < w && a[tmp.x][tmp.y + 1] && (!visited[tmp.x][tmp.y + 1]))
q.push({tmp.x,tmp.y + 1,tmp.energy - 1});
}
memset(visited,0,sizeof visited);
}
//对着药物的图论网络开始广搜,看看能不能搜到终点
queue<int> q;
//起初的药物点
q.push(mp[begx][begy]);
while (q.size())
{
tmp2 = q.front();
q.pop();
//如果已经到终点
if (tmp2 == n + 1)
{
puts("Yes");
return 0;
}
//打标记
visited2[tmp2] = 1;
//扩展
for (auto p : v[tmp2])
if (!visited2[p]) q.push(p);
}
puts("No");
}