F. The Beach codeforces1754F

10 篇文章 0 订阅

Problem - F - Codeforces

题目大意:有一个n*m的迷宫,'#'为不可移动的障碍物,'LR'和'UD'是可以花费p平移或花费q旋转的障碍物,LR可以横向平移,UD可以纵向平移,旋转可以按任意方向旋转到四格内没有其他障碍物的地方,目标是要使两个'.'相遇,问最小费用

1<=n<=3e5;1<=m<=3e5;1<=n*m<=3e5;1<=p,q<=1e9

思路:我们考虑枚举每一个'.',看将它移动到每个可到达的位置的最小费用是多少,然后再枚举每两个相邻的'.'的花费之和的最小值即可

我们考察每个'.'能够去的位置,如果是平移的话,如果'.'的右边是'L',那么让'LR‘向左移就可以使得这个'.'向右移两格,移到原来'R'的位置,花费为q,同理,如果左边是'R',上边是'D',下边是'U'的话,同样也可以使'.'向对应方向移两格。

 

然后考察旋转,如果上面或下面是'L',那么我们可以将'.'移到原来'R'的位置,即移到右上或右下,如果上或下面是'R',那么可以移到左上或左下,如果右边或左边是'U’,可以移到右下或左下,如果右边或左边是'D',可以移到左上或右上,费用为q

那么我们可以维护每一个位置,如果有某个'.'能到达,那么最小花费是多少,所以我们从每一个'.'开始遍历,初始花费为0,用优先队列储存当前每个'.'的位置和已用花费,看队头已用花费最小的'.'去往所有可能的位置的花费,如果他去往目的地比已保存的更小,就更新目的地的花费信息,如果当前队头元素的已用花费大于他所在位置的已记录花费,则说明其他点到这里费用更小,后序操作费用肯定比其他点费用大,直接丢弃该点,这样就能使时间复杂度优化到近似O(nmlog(nm))

#include<iostream>
#include<cstdio>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
const ll N = 3e5 + 5, INF = 1e18;
string ma[N];
map<pair<int, int>, ll> co;
int n, m;
bool check(int i, int j)
{//检查要到达的点还在不在迷宫内
	return i >= 0 && i <= n - 1 && j >= 0 && j <= m - 1;
}
struct cmp
{//每个点的到达费用从小到大排序
	bool operator()(pair<pair<int, int>, ll>a, pair<pair<int, int>, ll>b)
	{
		return a.second > b.second;
	}
};
int main()
{
	ios::sync_with_stdio(false);
	cin >> n >> m;
	ll p, q;
	cin >> p >> q;
	priority_queue < pair<pair<int, int>, ll>,vector<pair<pair<int, int>, ll>>,cmp> qu;//储存每个'.'的当前位置和到这个位置的已用花费
	for (int i = 0; i < n; i++)
	{
		cin >> ma[i];
		for (int j = 0; j < m; j++)
		{
			if (ma[i][j] == '.')
			{
				qu.push(make_pair(make_pair(i, j), 0));
				co[make_pair(i, j)] = 0;//记录每一个点将'.'移到该点的花费,如果这个点是'.'就初始化为0
			}
			else
				co[make_pair(i, j)] = INF;//不是'.',初始化为极大值
		}
	}
	while (!qu.empty())
	{
		int i = qu.top().first.first, j = qu.top().first.second;
		ll c = qu.top().second;
		qu.pop();
		if (c > co[make_pair(i, j)])
			continue;//有其他'.'到这个位置费用更小了,这个'.'就可以丢弃了
		if (check(i, j + 1) && ma[i][j + 1] == 'L' && check(i, j + 2))
		{//右边是'L',向右平移两格
			if (c + q < co[make_pair(i, j + 2)])
			{//当前已用费用+q是不是比其他'.'到目标点费用更小
				co[make_pair(i, j + 2)] = c + q;
				qu.push(make_pair(make_pair(i, j + 2), c + q));
			}
		}
		if (check(i + 1, j) && ma[i + 1][j] == 'U' && check(i + 2, j))
		{//下边是'U',向下移两格
			if (c + q < co[make_pair(i + 2, j)])
			{
				co[make_pair(i + 2, j)] = c + q;
				qu.push(make_pair(make_pair(i + 2, j), c + q));
			}
		}
		if (check(i, j - 1) && ma[i][j - 1] == 'R' && check(i, j - 2))
		{//左边是'R',向左移两格
			if (c + q < co[make_pair(i, j - 2)])
			{
				co[make_pair(i, j - 2)] = c + q;
				qu.push(make_pair(make_pair(i, j - 2), c + q));
			}
		}
		if (check(i - 1, j) && ma[i - 1][j] == 'D' && check(i - 2, j))
		{//上边是'D',向上移两格
			if (c + q < co[make_pair(i - 2, j)])
			{
				co[make_pair(i - 2, j)] = c + q;
				qu.push(make_pair(make_pair(i - 2, j), c + q));
			}
		}
		if (check(i + 1, j) && ma[i + 1][j] == 'L' && check(i + 1, j + 1))
		{//下边是'L',移到右下
			if (c + p < co[make_pair(i + 1, j + 1)])
			{
				co[make_pair(i + 1, j + 1)] = c + p;
				qu.push(make_pair(make_pair(i + 1, j + 1), c + p));
			}
		}
		if (check(i - 1, j) && ma[i - 1][j] == 'L' && check(i - 1, j + 1))
		{//上边是'L',移到右上
			if (c + p < co[make_pair(i - 1, j + 1)])
			{
				co[make_pair(i - 1, j + 1)] = c + p;
				qu.push(make_pair(make_pair(i - 1, j + 1), c + p));
			}
		}
		if (check(i - 1, j) && ma[i - 1][j] == 'R' && check(i - 1, j - 1))
		{//上边是'R',移到左上
			if (c + p < co[make_pair(i - 1, j - 1)])
			{
				co[make_pair(i - 1, j - 1)] = c + p;
				qu.push(make_pair(make_pair(i - 1, j - 1), c + p));
			}
		}
		if (check(i + 1, j) && ma[i + 1][j] == 'R' && check(i + 1, j - 1))
		{//下边是'R',移到左下
			if (c + p < co[make_pair(i + 1, j - 1)])
			{
				co[make_pair(i + 1, j - 1)] = c + p;
				qu.push(make_pair(make_pair(i + 1, j - 1), c + p));
			}
		}
		if (check(i, j + 1) && ma[i][j + 1] == 'U' && check(i + 1, j + 1))
		{//右边是'U',移到右下
			if (c + p < co[make_pair(i + 1, j + 1)])
			{
				co[make_pair(i + 1, j + 1)] = c + p;
				qu.push(make_pair(make_pair(i + 1, j + 1), c + p));
			}
		}
		if (check(i, j - 1) && ma[i][j - 1] == 'U' && check(i + 1, j - 1))
		{//左边是'U',移到左下
			if (c + p < co[make_pair(i + 1, j - 1)])
			{
				co[make_pair(i + 1, j - 1)] = c + p;
				qu.push(make_pair(make_pair(i + 1, j - 1), c + p));
			}
		}
		if (check(i, j + 1) && ma[i][j + 1] == 'D' && check(i - 1, j + 1))
		{//右边是'D',移到右上
			if (c + p < co[make_pair(i - 1, j + 1)])
			{
				co[make_pair(i - 1, j + 1)] = c + p;
				qu.push(make_pair(make_pair(i - 1, j + 1), c + p));
			}
		}
		if (check(i, j - 1) && ma[i][j - 1] == 'D' && check(i - 1, j - 1))
		{//左边是'D',移到左上
			if (c + p < co[make_pair(i - 1, j - 1)])
			{
				co[make_pair(i - 1, j - 1)] = c + p;
				qu.push(make_pair(make_pair(i - 1, j - 1), c + p));
			}
		}
	}
	ll ans = INF;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			if (j != m - 1)
			{
				ans = min(ans, co[make_pair(i, j)] + co[make_pair(i, j + 1)]);//枚举每两个横向相邻的位置的到达所需费用和
			}
			if (i != n - 1)
			{
				ans = min(ans, co[make_pair(i, j)] + co[make_pair(i + 1, j)]);//枚举每两个纵向相邻的位置的到达所需费用和
			}
		}
	}
	cout << (ans == INF ? -1 : ans);//如果答案在枚举过程中没有更新,说明无法是两个'.'移到相邻位置
	return 0;
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

timidcatt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值