题意:
你站在一个r*c的森林里面,每一个可能是树(人不能经过该点),还有一些你的敌人,这些敌人可以多个人再一个格子里面,他们就是要阻止你到达森林的出口,所以会尽力拦截你(你们每次可以移动到相邻的格子),你遇到他们就要和他们战斗,问你最少和所少敌人战斗?
思路:
首先,假设你有一条到终点的路径x,他们可能在路径x的任意一个节点上拦截你,假设他可以在路径x的某一点拦截到你,说明敌人比你先到这个节点。然而,由于你的路径是不确定的,而且拦截你的节点也是不确定的,所以要转化到确定的节点,路径x唯一确定的就是你的起点和终点。那么就往终点上想。
既然敌人比你先到路径X上的点P,那么接下来他可以按照你的路径走到终点,也就是说,敌人会比你先到终点,这样路径上的其他不确定的点全部转化为了终点这个确定的点。
问题转化为谁先到达终点,能比你先到终点的敌人就可以和你战斗。这个时候从终点反向BFS即可(因为终点只有一个,其他点有很多个),就可以了。
转化与化归的思想,从变化中寻找不变量,把不确定转化为确定。
AC CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
typedef long long LL;
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define mem(a,b) memset(a,b,sizeof(a))
#define per(i,a,b) for(int i = a;i <= b;++i)
#define rep(i,a,b) for(int i = a;i >= b;--i)
const int maxn = 1e3;
int r = 0,c = 0;
char str[maxn+10][maxn+10];
bool vis[maxn+10][maxn+10];
//int ex = 0,ey = 0,sx = 0,sy = 0;//不需要
int ans = 0;
int dx[4] = {0,1,0,-1};
int dy[4] = {1,0,-1,0};
void bfs(int x,int y){
memset(vis,false,sizeof(vis));
queue<pii> que;
que.push(pii(x,y));
vis[x][y] = true;
int cnt = 1;
bool flag = false;
while(!que.empty()){
int end = cnt;
cnt = 0;
while(end--){//遍历同一层节点,因为同一层节点离E得距离一样,
//可以判断它是否可以拦截
pii p = que.front();que.pop();
int x1 = p.first,y1 = p.second;
per(i,0,3){
int tx = x1 + dx[i],ty = y1 + dy[i];
if(tx >= r || tx < 0 || ty >= c || ty < 0 || vis[tx][ty] == true
|| str[tx][ty] == 'T'){
continue;
}
if(str[tx][ty] == 'S'){
flag = true;
}
if(str[tx][ty] > '0' && str[tx][ty] <= '9'){
ans += (str[tx][ty] - '0');
}
vis[tx][ty] = true;
que.push(pii(tx,ty));
++cnt;
}
}
if(flag == true){
return ;
}
}
}
int main(){
while(~scanf("%d %d",&r,&c)){
ans = 0;
per(i,0,r-1){
scanf("%s",str[i]);
}
per(i,0,r-1){
per(j,0,c-1){
if(str[i][j] == 'E'){//不需要记录起点和终点,从终点开始BFS,
//遍历过程碰到S再退出
bfs(i,j);
//break;
i = r;j = c;//退出两重循环的好办法
}
}
}
printf("%d\n",ans);
}
return 0;
}