!Gym 100625J 狱警放两犯人的最小开门数-bfs-(优先队列+bfs,求各自到交点的距离)

题意:二维矩阵,狱警从外面到里面去放两个犯人,问中途需要开的门的最小的次数。

分析:

这题从外面进去,那么只要是矩阵边缘可走的点(除了墙壁的点)都可作为起点,还有两个终点,所以直接枚举起点再搜索是不可行的。这题的做法是用三次bfs,分别求得从外面到每一个可走点的最小距离(开门次数)、两个犯人到每个可走点的最小距离,然后遍历一遍矩阵,把三个距离加起来,更新答案即可。求矩阵外面到矩阵里的最小距离是这么处理的:在输入的矩阵外面加上一圈可走点,然后从(0,0)的位置开始bfs即可(这样处理还有一个原因是最优解的交点可能不在输入矩阵的里面,而在外面)。

因为这里的最小距离不是走的步数而是开门次数,所以bfs要用优先队列,不然就会WA.

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#define INF 1000000007
using namespace std;
int t,n,m;
char a[200][200];
int d[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int vis[200][200];
int dis[4][200][200];
struct node{
	int x,y;
	node(int x,int y):x(x),y(y){};
};
struct qnode{
	int x,y;
	int d;
	qnode(int x,int y,int d):x(x),y(y),d(d){}
	friend bool operator<(const qnode &a,const qnode &b){
		return a.d>b.d;
	}
};
priority_queue<qnode> q;
void bfs(int x,int y,int p)
{
	memset(vis,0,sizeof(vis));
	while(!q.empty()) q.pop();
	qnode tp=qnode(x,y,0);
	q.push(tp);
	vis[x][y]=1;
	while(!q.empty()){
		qnode tmp=q.top();
		q.pop();
		for(int i=0;i<4;i++){
			int dx=tmp.x+d[i][0];
			int dy=tmp.y+d[i][1];
			if(dx>=0&&dx<=n+1&&dy>=0&&dy<=m+1&&a[dx][dy]!='*'&&!vis[dx][dy]){
				vis[dx][dy]=1;

				if(a[dx][dy]=='#') dis[p][dx][dy]=dis[p][tmp.x][tmp.y]+1;
				else dis[p][dx][dy]=dis[p][tmp.x][tmp.y];
				qnode tmp1=qnode(dx,dy,dis[p][dx][dy]);
				q.push(tmp1);
			}
		}
	}
}
int main()
{
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&n,&m);
		int ex1=-1,ey1=-1,ex2,ey2;
		for(int i=0;i<=n+1;i++) a[i][0]='.',a[i][m+1]='.';
		for(int i=0;i<=m+1;i++) a[0][i]='.',a[n+1][i]='.';
		for(int i=1;i<=n;i++) scanf("%s",a[i]+1);
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				if(a[i][j]=='$'){
					if(ex1==-1) ex1=i,ey1=j;
					else ex2=i,ey2=j;
				}
			}
		}
		memset(dis,0,sizeof(dis));
		bfs(0,0,0);
		bfs(ex1,ey1,1);
//		for(int i=0;i<n;i++){
//		for(int j=0;j<m;j++) cout<<dis[1][i][j];cout<<endl;}
		bfs(ex2,ey2,2);
		int ans=INF;
		for(int i=0;i<=n+1;i++){
			for(int j=0;j<=m+1;j++){
				if(a[i][j]=='.'||a[i][j]=='$'){
					int sum=0;
					for(int k=0;k<3;k++){
						sum+=dis[k][i][j];
					}
					ans=min(ans,sum);
				}
				else if(a[i][j]=='#'){
					int sum=0;
					for(int k=0;k<3;k++){
						sum+=dis[k][i][j];
					}
					ans=min(ans,sum-2);
				}
			}
		}
		cout<<ans<<endl;
	}
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-21 08:49:38

!Gym 100625J 狱警放两犯人的最小开门数-bfs-(优先队列+bfs,求各自到交点的距离)的相关文章

2015 湘潭大学程序设计比赛(Internet)Problem D:最小的数

今天的比赛,因为时间问题,我就做了这一个题 题目描述 给你一个n位数,每次操作可以选该数任意的相邻两位进行交换,如果最多可以操作k次,那么最终可以得到的最小的数是什么 (n位且不能含前导零)? 输入 有多组测试数据,第一行为数据个数T(T<=10); 每组数据占一行,包含一个数(不超过1000位)和k(0<=k<=1000),中间用空格隔开; 输出 最终能得到的最小的数. 样例输入 2 321654987 1 321654987 2 样例输出 231654987 132654987 这个

poj3422 拆点法x-&gt;x&#39;建立两条边+最小费用最大流

/** 题目:poj3422 拆点法+最小费用最大流 链接:http://poj.org/problem?id=3422 题意:给定n*n的矩阵,含有元素值,初始sum=0.每次从最左上角开始出发,每次向右或者向下一格.终点是右下角. 每经过一个格子,获取它的值,并把该格子的值变成0.问经过k次从左上角到右下角.能得到的数值和最大多少. 思路:我觉得本题元素值全是非负数.要不然不可以过.很多网上的博客代码在有负数情况下过不了. 拆点法+最小费用最大流 建图: 每一个格子x,拆成x,xi, x向x

汇编语言实现求两个数的最小公约数,平方差,各占和的百分比

按下列要求编程: (1)输入两个小于100的十进制正整数. (2)求出这两个数的所有公约数. (3)求出这两个数的平方差,若是负的要输出负号. (4)计算两个数各占和的百分比,并且按照“ %”的格式输出(小数点后保留两位). (5)数据的输入和结果的输出都要有必要的提示,且提示独占一行. (6)要使用到子程序. ? 源代码: 1 data segment 2 hh db 0dh,0ah,'$' 3 m1 db 'please enter a number:',0dh,0ah,'$' 4 m2 d

STL--H - Black Box(两个优先队列,求第k小的值)

H - Black Box Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Description Our Black Box represents a primitive database. It can save an integer array and has a special i variable. At the initial moment Black

【编程题目】把数组排成最小的数

68.把数组排成最小的数(数组.算法).题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个.例如输入数组{32, 321},则输出这两个能排成的最小数字 32132.请给出解决问题的算法,并证明该算法. 思路:首先,肯定要考虑溢出问题.开始想用字符串,后来改为了用list.思路是先把第一个数字放入list,然后依次把后面的数字插入到合适的位置. 关键问题就是如何判断两个数字哪一个在前面. ①对于 353 .412这样的情况,肯定是第一个数字小的在前面 ②遇到数字

百度:求绝对值最小的数

我只是从网上搜集的,下面的代码或许有错误. 看了会Hadoop,和传华聊了会,他说,他们那三等奖8000,:打算要回宿舍了,不经意间看到了这个题,貌似简单,其实还是比较有难度的. 一段时间只能干一件事就行了. 有一个已经排序的数组(升序),数组中可能有正数.负数或0,求数组中元素的绝对值最小的数,要求,不能用顺序比较的方法(复杂度需要小于O(n)),可以使用任何语言实现,例如,数组{-20,-13,-4, 6, 77,200} ,绝对值最小的是-4. 算法实现的基本思路:找到负数和正数的分界点,

51Nod - 1097 拼成最小的数

51Nod - 1097 拼成最小的数 设有n个正整数,将它们联接成一排,组成一个最小的多位整数. 例如: n=2时,2个整数32,321连接成的最小整数为:32132, n=4时,4个整数55,31,312, 33 联接成的最小整数为:312313355 Input 第1行:1个数N.(2 <= N <= 10000) 第2 - N + 1行:每行1个正整数.(1 <= A[i] <= 10^9) Output 输出拼在一起的最小整数.由于数据量太大,请以1000个字符为单位,输

Min Number 贪心,把最小的数放在最前

题目链接 Problem 2111 Min Number Accept: 499    Submit: 949 Time Limit: 1000 mSec    Memory Limit : 32768 KB Problem Description Now you are given one non-negative integer n in 10-base notation, it will only contain digits ('0'-'9'). You are allowed to c

剑指OFFER之把数组排成最小的数(九度OJ1504)

题目描述: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. 输入: 输入可能包含多个测试样例.对于每个测试案例,输入的第一行为一个整数m (1<=m <=100)代表输入的正整数的个数.输入的第二行包括m个正整数,其中每个正整数不超过10000000. 输出: 对应每个测试案例,输出m个数字能排成的最小数字. 样例输入: 3 23 13 6 2 23456 56 样