Eight Point Sets-Codeforces 反向BFS

题意:
你站在一个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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值