首页 > 其他 > 详细

多维建图 1

时间:2020-11-14 11:08:55      阅读:39      评论:0      收藏:0      [点我收藏+]

例题:
题目描述
迷宫用 n*mn?m 的网格表示,分为以下四种格子:

X:墙,不能通过
.:空地,可以通过
^:陷阱(开启):可以通过,但行动后如果处在开启的陷阱上上会额外消耗1点体力
_:陷阱(关闭):可以通过
每次你可以从当前格子花费1点体力进行一次行动,包括移动到上下左右四方向的某一个可以通过的格子,或者停留在原地。

在每次行动时,所有陷阱的状态会在开启和关闭之间切换。如果相邻格子当前为一开启的陷阱,当你移动到上面时它会关闭,所以不会额外消耗体力。反之如果相邻一个当前关闭的陷阱,则移动到上面需要额外消耗1体力。

你的起点为迷宫左上角,终点为迷宫右下角,你需要找到一个消耗体力值最少的行动方法。

保证起点和终点处为空地。
输入格式
第一行两个整数n, mn,m,分别表示迷宫的行数和列数

接下来nn行mm列,每个字符代表一个格子,见题目描述,表示开始时迷宫的状态

输出格式
一行一个整数,表示最少消耗的体力
输入输出样例
输入 #1
5 5
.....
^XXX.
_X...
.X.XX
^....

输出 #1
9

显然,走的步数是奇数步时,地图状态都一样;走了偶数步时,地图状态也都一样。在没有陷阱的情况下,我们可以通过建一个两层的二维图,第一层为偶数层(因为从0步开始,0为偶数),第二层为奇数层。每走一步,就去到另一个层的对应点,如图:
技术分享图片

当有陷阱时,我们有两种决策,第一种是做一次停留,另一种是踩进陷阱并因此额外耗费一点体力。
当停留时,位置没有改变,但是因为停留也是一种行动,步数的奇偶性仍会发生改变,因此,在二维图中,所处的维度会去到另一层,如图:
技术分享图片

当踩入陷阱时,会额外耗费一点体力,相当于做了一次行动却耗费了两点体力,那么,我们可以通过建立一个第三维度,当在所处维度踩到陷阱时,再耗费一点体力去到第三维度的对应位置,然后从第三维度的对应位置再耗费一点体力去到下一个对应的维度。因为在同一个陷阱上停留是没有意义的,所以不考虑第三维度的停留问题。
当在偶数维度踩到陷阱时,建立一条从当前的点到第三维度对应点的边,再建立一条从第三维度对应点到奇数维度下一个点的边,用来等效额外的体力消耗。奇数维度时如法炮制。
如图:
技术分享图片

代码实现:

#include<cstring>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;

const int maxn=510;

int n,m,pow[maxn*maxn*3],dx[4]={-1,1,0,0},dy[4]={0,0,-1,1},ed0,ed1,ans;
vector <int> e[maxn*maxn*3];
queue <int> q;
char str[maxn][maxn];

void ist(int u,int v)
{
	e[u].push_back(v);
}

void bfs()
{
	q.push(0);
	while(!q.empty())
	{
		int t=q.front();
		q.pop();
		
		if(t==ed0 || t==ed1) return;//只要第一次到达了终点,那么此时体力耗费一定最小 
		
		for(int i=0;i<e[t].size();i++)
		{
			int to=e[t][i];
			if(pow[to]<0)
			{
				pow[to]=pow[t]+1;
				q.push(to);
			}
		}
	}
}

int main()
{
	scanf("%d %d",&n,&m);
	for(int i=0;i<n;i++)
	{
		scanf("%s",str[i]);
	}
	
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			int s0=(i*m+j)*3,s1=s0+1;//将三维坐标压缩成一维坐标 
			
			if(str[i][j]==‘X‘) continue;
			ist(s0,s1),ist(s1,s0);//在s0和s1之间建一条双向边,因为在任意状态都可以停留 
			if(str[i][j]==‘^‘)
			{
				ist(s0,s0+2);
				//在走了偶数步时踩到陷阱,还需要在在偶数维度和第三维度之间建一条单向边,等效替代踩到陷阱时多消耗的体力
				//在同一个陷阱上消耗两次体力是没有意义的,所以只建单向边 
				s0+=2;//去到第三维度 
			}
			if(str[i][j]==‘_‘)
			{
				ist(s1,s1+1);//走了奇数步踩到陷阱,在奇数维度和第三维度之间建一条边 
				s1++;//去到第三维度 
			}
			
			for(int k=0;k<4;k++)
			{
				int mx=i+dx[k],my=j+dy[k];
				if(mx<0 || mx>=n || my<0 || my>=m || str[mx][my]==‘X‘) continue;
				int t0=(mx*m+my)*3,t1=t0+1;
				ist(s0,t1),ist(s1,t0);//当前是奇维度,下一步就走向偶维度;反之亦然 
			}
		}
	}
	
	ed0=((n-1)*m+m-1)*3,ed1=ed0+1;//终点的一维坐标 
	memset(pow,-1,sizeof(pow));
	pow[0]=0;
	bfs();
	
	if(pow[ed0]>0 && pow[ed1]>0) ans=min(pow[ed0],pow[ed1]);
	else if(pow[ed0]>0) ans=pow[ed0];
	else ans=pow[ed1];
	printf("%d\n",ans);
	
	return 0;
}

多维建图 1

原文:https://www.cnblogs.com/SeekHummingbird/p/13972429.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!