2020杭电多校 第四场 1004 Deliver the Cake(拆分点+堆优化最短路)

2020杭电多校 第四场 1004 Deliver the Cake(拆分点+堆优化最短路)

题目

http://acm.hdu.edu.cn/showproblem.php?pid=6805

题意

给出nn个村庄,每个村庄有一种特定的属性( leftl mid right)
left: 只有把货物放在左手的人才能进入此村庄
right: 只有把货物放在右手的人才能进入此村庄
mid: 把货物放在左手或右手都可以进入此村庄
给出村庄之间的路(双向边),和起点s终点t,以及把货物在左右手之间交换一次所需的时间x,求问从起点到终点最少需要多少时间(你可以自由选择起点时你的状态(左or右),但是你必须要满足这个村庄的属性
也就是说起点为leftleft或者rightright时,你必须要以这个状态出发,为midmid时你可以任选状态出发。

思路

2020杭电多校 第四场 1004 Deliver the Cake(拆分点+堆优化最短路)_第1张图片
我的思路就是按照题解来的,将邻接表扩大两倍maxn = 2e6+5,用2n表示左手拿着蛋糕去村庄,2n+1表示右手拿着蛋糕去村庄。为了避免起点和终点都是M村庄的时候,要多次使用Dijkstra,所以创建一个路径到起点为0的S点,和一个路径到终点为0的T点。因为0和1点用不上,所以S和T可以用这两个点来表示(我用的是0点和maxn-1)。
每组数据都要重新初始化一次vis[],dis[],G[]。为了尽量缩短时间复杂度,我在init()函数用的范围是0~n(每组数据的n),而不是maxn。

AC代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define INF 999999999999
#define ll unsigned long long
const int maxn  = 2e5+5;
const ll mod = 1e9+7;
struct Node
{
	int e;
	ll w;
	friend bool operator < (Node A, Node B)
	{
		return  A.w > B.w;
	}
};

bool vis[maxn];
vector<Node> G[maxn];
int n,m,s,t,x;
char str[maxn];
ll dis[maxn];
ll Dij(int Star,int End)
{
	Node P,Pn;
	P.e = Star;
	P.w = 0;
	dis[Star]=0;
	priority_queue<Node> Q;
	Q.push(P);
	while( !Q.empty() )
	{
		P = Q.top();
		Q.pop();
//		if(P.e==End)	return P.w;
		if( vis[P.e] )
			continue;
		vis[P.e] = true;
		int len = G[P.e].size();
//		printf("P.e = %d,size = %d\n",P.e,len);
		for(int i=0; i< len; i++)
		{
			Pn.e = G[P.e][i].e;
			Pn.w = G[P.e][i].w;
			if( !vis[Pn.e] && dis[Pn.e] > dis[P.e] + Pn.w)
			{
				dis[Pn.e] = dis[P.e] + Pn.w;
				Pn.w = dis[Pn.e];
//				printf("%d --> %d == %lld\n",P.e,Pn.e,dis[Pn.e]);
				Q.push(Pn);
			}
		}
	}
	return dis[End];
}
void init()
{
	for(int i=0;i<=2*n+1;i++)
	{
		G[i].clear();
		vis[i] = false;
		dis[i]=INF;
	}
	G[maxn-1].clear();
	vis[maxn-1] = false;
	dis[maxn-1] = INF;
}
int main()
{
//	freopen("Din.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d%d%d%d",&n,&m,&s,&t,&x);
		scanf("%s",str);
		init();
		while(m--)
		{
			int a,b,c;
			scanf("%d %d %d",&a,&b,&c);
			Node P;
			int a1=0,b1=0,a2=0,b2=0;
			if(str[a-1]!='R')	a1 = 2*a;//L M
			if(str[a-1]!='L') a2 = 2*a+1;//R M
			if(str[b-1]!='R')	b1 = 2*b;//L M
			if(str[b-1]!='L') b2 = 2*b+1;//R M
			if(a1!=0&&b1!=0)//L-->L
			{
				P.e=b1,P.w=c;
				G[a1].push_back(P);
				P.e=a1;
				G[b1].push_back(P);
			}
			if(a2!=0&&b2!=0)//R-->R
			{
				P.e=b2,P.w=c;
				G[a2].push_back(P);
				P.e=a2;
				G[b2].push_back(P);
			}
			if(a1!=0&&b2!=0)//L-->R
			{
				P.e=b2,P.w=c+x;
				G[a1].push_back(P);
				P.e=a1;
				G[b2].push_back(P);
			}
			if(a2!=0&&b1!=0)//R-->L
			{
				P.e=b1,P.w=c+x;
				G[a2].push_back(P);
				P.e=a2;
				G[b1].push_back(P);
			}
		}
		ll ans=-1;
		Node P;
		P.w=0;
		if(str[s-1]!='R')
		{
			P.e = 2*s;
			G[0].push_back(P);
		}
		if(str[s-1]!='L')
		{
			P.e = 2*s+1;
			G[0].push_back(P);
		}
		if(str[t-1]!='R')
		{
			P.e = maxn-1;
			G[2*t].push_back(P);
		}
		if(str[t-1]!='L')
		{
			P.e = maxn-1;
			G[2*t+1].push_back(P);
			
		}
		ans = Dij(0,maxn-1);
		printf("%lld\n",ans);
	}
	return 0;
}
/*
3
3 3 1 3 100
LRM
1 2 10
2 3 10
1 3 100

4 4 1 4 100
LRMR
1 2 10
2 3 10
3 4 10
1 3 18

4 4 1 4 100
LRLR
1 2 10
2 3 10
3 4 10
1 3 22
*/

你可能感兴趣的:(补题库,最短路堆优化)