题目大意:有一个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;
}