LA 4128 Steam Roller 拆点建图+迪杰斯特拉

LA 4128

题意:有一个r条横线和c条竖线组成的网格,你的任务是用最短时间从起点(r1,c1)走到终点(r2,c2),路上一些线段有权值代表时间,权值为0不能通过,刚出发和到达终点时,时间是权值的两倍,进入一条边之前转弯或者离开一条边以后立即需要转弯时,时间也是权值两倍。

思路:白书上的题,建图法相当妙,把每个点拆成8个点(r, c, dir, doubled),分别表示上一步从上下左右的哪个方向移动到这个点,以及移动到该点权值是否加倍,每个点有4个后继点,分别对应于上下左右,如果上一步的方向与后继点方向不一致,需要加倍这个上个点到点的权值,且如果上一步的权值没有加倍,就加倍上一步的权值,构建图成功后直接用dij()算法求出起点到各点的最短时间,最后统计到终点的答案时,特别要注意,由于到终点也要加倍权值,如果有没加倍的,要补上去。

#include
#include
#include
#include
#include
using namespace std;
const int maxn=1e5;
const int inf=1e9;
struct HeapNode
{
	int d,u;
	bool operator<(const HeapNode& rhs)const
	{
		return d>rhs.d;
	}
};
struct Edge
{
	int from,to,dist;
};
struct Dijkstra
{
	int n,m;
	vectoredges;
	vectorG[maxn];
	bool done[maxn];
	int d[maxn];
	int p[maxn];
	
	void init(int n)
	{
		this->n=n;
		for(int i=0;iQ;
		for(int i=0;id[u]+e.dist)
				{
					d[e.to]=d[u]+e.dist;
					p[e.to]=G[u][i];
					Q.push((HeapNode){d[e.to],e.to});
				}
			}
		}
	}
};
const int UP=0,LEFT=1,DOWN=2,RIGHT=3;
const int inv[4]={2,3,0,1};
const int dr[4]={-1,0,1,0};
const int dc[4]={0,-1,0,1};
const int maxr=100;
const int maxc=100;
int grid[maxr][maxc][4];
int R,C,n,id[maxr][maxc][4][2];
int ID(int r,int c,int dir,int doubled)
{
	int& x=id[r][c][dir][doubled];
	if(x==0)x=++n;
	return x;
}
bool cango(int r,int c,int dir)
{
	if(r<0||r>=R||c<0||c>=C)return false;
	return grid[r][c][dir]>0;
}
int readint()
{
	int x;scanf("%d",&x);return x;
}
Dijkstra solver;
int main()
{
	int r1,c1,r2,c2,kase=0;
	while(scanf("%d%d%d%d%d%d",&R,&C,&r1,&c1,&r2,&c2)==6&&R)
	{
		r1--,c1--,r2--,c2--;
		for(int r=0;r

你可能感兴趣的:(图论----最短路径)