【POJ3182】The Grove BFS 最短环绕路径

题意:给出一个N*M的图,其中‘X’表示树木(树木一定聚集在一起成为森林,不会分开),然后‘.’表示空地,‘*’表示起点,现在要求从起点出发,绕森林一圈,最后回到起点,所经过最少点数。

题目中给的‘+’就是其中一种最短路径。

题解:随便找一条经过森林且不经过起点的直线,可证路径一定会穿过这条直线,那么就在这条直线上枚举一个点,做两遍BFS,求其从分别直线两侧出发到起点的最短距离。

在这里说一个判断边界的简单方法,就是先给图里每个点打上标记,详见代码里‘in’数组,in值为0的自然就不再里面,而没有必要判断什么“1<=x&&x<=n&&……”。

好了,贴代码。

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 55
#define inf 0x3f3f3f3f
using namespace std;
const int dx[8]={-1,-1,-1,0,0,1,1,1};
const int dy[8]={-1,0,1,-1,1,-1,0,1};
struct Lux
{
	int x,y;
	Lux(int a,int b):x(a),y(b){}
	Lux(){}
};
char mp[N][N];
int map[N][N];/*0可行,1森林,2枚举线段,3起点*/
int n,m,ans=inf;
int dist[N][N],tx,ty;

int in[N][N],cnt;
queue<Lux>q;
int bfs(int sx,int sy)
{
	int i,fr,ret;
	int vx,vy;

	for(ret=fr=0;fr<2;fr++)
	{
		memset(dist,0x3f,sizeof(dist));
		while(!q.empty())q.pop();
		for(i=fr*5;i<fr*5+3;i++)
		{
			vx=sx+dx[i];
			vy=sy+dy[i];
			if(in[vx][vy]&&!map[vx][vy])dist[vx][vy]=1,q.push(Lux(vx,vy));
		}
		while(!q.empty())
		{
			Lux U=q.front();q.pop();
			for(i=0;i<8;i++)
			{
				vx=U.x+dx[i];
				vy=U.y+dy[i];
				if(in[vx][vy]&&!map[vx][vy]&&dist[vx][vy]>dist[U.x][U.y]+1)
				{
					dist[vx][vy]=dist[U.x][U.y]+1;
					q.push(Lux(vx,vy));
				}
			}
		}
		ret+=dist[tx][ty];
	}
	return ret;
}
int main()
{
//	freopen("test.in","r",stdin);
	int i,j,x,y;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)scanf("%s",mp[i]+1);
	for(j=1;j<=m;j++)for(i=1;i<=n;i++)
	{
		in[i][j]=++cnt;
		if(mp[i][j]=='X')
		{
			map[i][j]=1;
			x=i;y=j;
		}
		else if(mp[i][j]=='*')tx=i,ty=j;
	}
	if(tx==x&&ty>y)
	{
		for(i=y;mp[x][i]=='X';i--);
		y=i;
		for(i=y;i;i--)map[x][i]=3;
		for(i=y;i;i--)ans=max(ans,bfs(x,i));
	}
	else
	{
		for(i=y+1;i<=m;i++)map[x][i]=3;
		for(i=y+1;i<=m;i++)ans=min(ans,bfs(x,i));
	}
	printf("%d\n",ans);
	return 0;
}
时间: 2024-12-19 20:54:26

【POJ3182】The Grove BFS 最短环绕路径的相关文章

搜索(BFS)---最短单词路径

最短单词路径 127. Word Ladder (Medium) Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] Output: 5 Explanation: As one shortest transformat

编程实现求一棵二叉树的最短树路径和最长树路径

Minimum Depth of Binary Tree Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node. class Solution { public: int minDepth(TreeNode *root) { if(!r

最短Hamilton路径-状压dp解法

最短Hamilton路径 时间限制: 2 Sec  内存限制: 128 MB 题目描述 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次. 输入 第一行一个整数n. 接下来n行每行n个整数,其中第i行第j个整数表示点i到j的距离(一个不超过10^7的正整数,记为a[i,j]). 对于任意的x,y,z,数据保证 a[x,x]=0,a[x,y]=a

最短Hamilton路径

题目描述 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次. 输入 第一行一个整数n. 接下来n行每行n个整数,其中第i行第j个整数表示点i到j的距离(一个不超过10^7的正整数,记为a[i,j]). 对于任意的x,y,z,数据保证 a[x,x]=0,a[x,y]=a[y,x] 并且 a[x,y]+a[y,z]>=a[x,z]. 输出 一个整数

Contest Hunter 0103 最短Hamilton路径 - 状压DP

传送门 思路: 1.状态:由于经过的点是一个集合,所以我们用dis[i][j]表示经过的点的状态为i,且当前位于点j时的最短Hamilton路径,其中i为一个二进制整数,用来存储经过的点的情况.为了方便位运算,我们的点的标号为0~n-1. 2.边界:dis[1][0]表示当前在起点0的最短Hamilton路径. 最终答案在dis[(1<<n)-1][n-1],即0~n-1所有点都被经过了一遍,当前在终点n-1的最短Hamilton路径. 3.决策:对于两点i,j,有两种决策:一是直接通过当前求

P1171 售货员的难题 - 状压DP【最短Hamilton路径】

P1171 售货员的难题 Sol: 最短Hamilton路径,经典的NPC问题,小数据可以通过状压DP 实现. 状态:\(f[i][j]\)表示当前在第i号点,且已经过的点的状态为j 时的最短Hamilton路径. 阶段:若以点为阶段,由于会从点i转移到点i+1,还可能从i+1转移到i-1,不具有无后效性,因此我们考虑以二进制状态为阶段进行转移. 决策:考虑由哪一个点转移而来. 转移:\(f[i][j]=\max \limits_{i\&(1<<i)\&\&i\&

『最短Hamilton路径 状态压缩DP』

状压DP入门 最短Hamilton路径 Description 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次. Input Format 第一行一个整数n. 接下来n行每行n个整数,其中第i行第j个整数表示点i到j的距离(一个不超过10^7的正整数,记为a[i,j]). 对于任意的x,y,z,数据保证 a[x,x]=0,a[x,y]=a[y

位运算 - 最短Hamilton路径

给定一张 n 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamilton路径的定义是从 0 到 n-1 不重不漏地经过每个点恰好一次. 输入格式 第一行输入整数n . 接下来n 行每行n个整数,其中第i行第j个整数表示点i到j 的距离(记为a[i,j]). 对于任意的x,y,z ,数据保证 a[x,x]=0,a[x,y]=a[y,x] 并且 a[x,y]+a[y,z]>=a[x,z]. 输出格式 输出一个整数,表示最短Hamilton路径

# 最短Hamilton路径(二进制状态压缩)

最短Hamilton路径(二进制状态压缩) 题目描述:n个点的带权无向图,从0-n-1,求从起点0到终点n-1的最短Hamilton路径(Hamilton路径:从0-n-1不重不漏的每个点恰好进过一次) 题解:二进制状态压缩算法\(O(2^n*n^2)\),需要记录当前经过了哪些点,当前在哪个位置.\(f[i][j]\) ? \(i\)转化为二进制每一位代表是否经过该点,\(j\)表示当前位于j这个点 #include <iostream> #include <cstring> u