HDU 多校联赛第四场 Deliver the Cake

由于之前不会堆优化版本的 d i j s t r a dijstra dijstra,只会 s p f a spfa spfa算法,然后补题的时候想着用 s p f a spfa spfa算法过,没想到被卡了,所以去学了一手 d i j s t r a dijstra dijstra

这里讲一下两种算法的时间复杂度:
s p f a : spfa: spfa:核心思想 b f s bfs bfs,时间复杂度,不好证明,这算法写起来挺简单的,跑随机图飞快,但出题人刻意卡的话,那这个算法就不行了。
d i j s t r a dijstra dijstra: 核心思想贪心,时间复杂度 O n ( l o g n ) On(logn) On(logn),用了优先队列,优化了普通 d i j s t r a dijstra dijstra找最小点距的位置

D e l i v e r t h e C a k e Deliver the Cake DelivertheCake

思路:
由于有 M M M的存在,图的就出现了多种可能性,所以我们需要把这些可能性考虑出来,然后将 M M M点拆开,然后建图, M M M L R L R LR两种可能,所以我们就需要考虑当 M M M L ∣ R L|R LR时,图的边权值了,这里我们可以将 M M M R R R时的点映射为 R ( u ) + n R(u)+n R(u)+n,然后还有一种情况,若起始点为 M M M,或终点为 M M M时,我们将起始点设置为 0 0 0,终点设置为 ( 2 n + 1 ) (2n+1) (2n+1),这样就不会影响拆点。

拆点代码

if ((dir[u] == 'L' && dir[v] == 'R') || (dir[u] == 'R' && dir[v] == 'L'))
        addT(u, v, w + x);
else if ((dir[u] == 'L' && dir[v] == 'L') || (dir[u] == 'R' && dir[v] == 'R'))
        addT(u, v, w);
else if (dir[u] == 'M' && dir[v] == 'L')
        addT(u, v, w), addT(u + n, v, w + x);
else if (dir[u] == 'M' && dir[v] == 'R')
        addT(u + n, v, w), addT(u, v, w + x);
else if (dir[u] == 'L' && dir[v] == 'M')
        addT(u, v, w), addT(u, v + n, w + x);
else if (dir[u] == 'R' && dir[v] == 'M')
        addT(u, v + n, w), addT(u, v, w + x);
else if ((dir[u] == 'M' && dir[v] == 'M'))
        addT(u, v, w), addT(u + n, v + n, w), addT(u, v + n, w + x), addT(u + n, v, w + x);

参考代码:

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <math.h>
using namespace std;
//typedef long long ll;
#define int long long
const int N = 1e3 + 5;
const int maxn = 2e6 + 20;
const int mod = 1e9 + 7;
int inv[maxn], dp[maxn], vis[maxn], dis[maxn];
vector<int> vec;
typedef pair<int, int> p;
int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
int lcm(int a, int b) { return a * b / gcd(a, b); }
struct node
{
    int v, w, nex;
} edge[maxn];
int cnt, head[maxn], x, s, t, n, m;
char dir[maxn];
priority_queue<p, vector<p>, greater<p> > q;
void add(int u, int v, int w)
{
    edge[cnt].w = w, edge[cnt].v = v, edge[cnt].nex = head[u];
    head[u] = cnt++;
}
void addT(int u, int v, int w)
{
    add(u, v, w), add(v, u, w);
}
void dij()
{
    memset(vis, 0, sizeof vis);
    memset(dis, 0x3f3f3f3f, sizeof dis);
    if (dir[s] == 'M')
        q.push({0, 0}), dis[0] = 0;
    else
        q.push({0, s}), dis[s] = 0;
    while (!q.empty())
    {
        p t = q.top();
        q.pop();
        int u = t.second;
        if (vis[u])
            continue;
        vis[u] = 1;
        for (int i = head[u]; ~i; i = edge[i].nex)
        {
            int v = edge[i].v, w = edge[i].w;
            if (dis[v] > dis[u] + w)
            {
                dis[v] = dis[u] + w;
                q.push({dis[v], v});
            }
        }
    }
    if (dir[t] == 'M')
        cout << dis[2 * n + 1] << endl;
    else
        cout << dis[t] << endl;
}
void init()
{
    cnt = 0;
    memset(head, -1, sizeof head);
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int q, u, v, w;
    cin >> q;
    while (q--)
    {
        init();
        cin >> n >> m >> s >> t >> x;
        cin >> (dir + 1);
        if (dir[s] == 'M')
            addT(s, 0, 0), addT(0, s + n, 0);
        if (dir[t] == 'M')
            addT(t, 2 * n + 1, 0), addT(t + n, 2 * n + 1, 0);
        for (int i = 1; i <= m; i++)
        {
            cin >> u >> v >> w;
            if ((dir[u] == 'L' && dir[v] == 'R') || (dir[u] == 'R' && dir[v] == 'L'))
                addT(u, v, w + x);
            else if ((dir[u] == 'L' && dir[v] == 'L') || (dir[u] == 'R' && dir[v] == 'R'))
                addT(u, v, w);
            else if (dir[u] == 'M' && dir[v] == 'L')
                addT(u, v, w), addT(u + n, v, w + x);
            else if (dir[u] == 'M' && dir[v] == 'R')
                addT(u + n, v, w), addT(u, v, w + x);
            else if (dir[u] == 'L' && dir[v] == 'M')
                addT(u, v, w), addT(u, v + n, w + x);
            else if (dir[u] == 'R' && dir[v] == 'M')
                addT(u, v + n, w), addT(u, v, w + x);
            else if ((dir[u] == 'M' && dir[v] == 'M'))
                addT(u, v, w), addT(u + n, v + n, w), addT(u, v + n, w + x), addT(u + n, v, w + x);
        }
        dij();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值