車での移動(アルゴリズムの競合、DPの乗算、最適化に関する高度なガイド)

1.タイトルリンク:

車で旅行

2.トピックの主なアイデア:

中国の質問は少し長いので、みんなを誤解させることはありません...

3.分析:

最初に金額を前処理します。

ga [i]:小さなAの次の都市である都市iから始まります。

gb [i]:小さなBの次の都市である都市iから始まります。

f [i] [j] [ k]:都市jから始めて、kは先に進み2 ^ i 、数がステップに達した後に都市を取り ます。

da [i] [j] [ k]:都市jから始めて、kが最初に進み 2 ^ i 、ステップに戻り、少しAの距離を移動しました。

db [i] [j] [ k]:都市jから始めて、kが最初に進み 2 ^ i 、ステップに戻り、小さなB距離が移動しました。 

上記の結果を得た後O(log_2x) 、乗算の時間の複雑さを使用して、それぞれ小さいAと小さいBが移動した距離見つけることができます 

上記の結果を解決する方法を以下に示します。

ga [i]:小さなAの次の都市である都市iから始まります。

gb [i]:小さなBの次の都市である都市iから始まります。

都市iを逆の順序で列挙すると、二分法により、高さが都市i以上の最初の都市を見つけることができます。

void init_g()
{
    set < pair <ll, int> > st;
    st.emplace(make_pair(inf, 0));
    st.emplace(make_pair(inf + 1, 0));
    st.emplace(make_pair(-inf, 0));
    st.emplace(make_pair(-inf - 1, 0));
    for(int i = n; i >= 1; --i)
    {
        auto j = st.lower_bound(make_pair(h[i], i));
        --j, --j;
        ll mn = inf, sm = inf;
        int mni, smi;
        for(int k = 0; k < 4; ++k)
        {
            auto p = *j;
            ll d = (ll)abs(p.first - h[i]);
            if(d < mn)
            {
                sm = mn, smi = mni;
                mn = d, mni = p.second;
            }
            else if(d < sm)
            {
                sm = d, smi = p.second;
            }
            ++j;
        }
        ga[i] = smi, gb[i] = mni;
        st.emplace(make_pair(h[i], i));
    }
}

 

f [i] [j] [ k]:都市jから始めて、kは先に進み2 ^ i 、数がステップに達した後に都市を取り ます。

i = 0:f [0] [j] [0] = ga [j]、f [0] [j] [1] = gb [j];

i = 1:f [1] [j] [k] = f [0、f [0] [j] [0]、1-k];

i> 1:f [i] [j] [k] = f [i-1] [f [i-1] [j] [k]] [k];

void init_f()
{
    for(int j = 1; j <= n; ++j)
    {
        f[0][j][0] = ga[j];
        f[0][j][1] = gb[j];
    }
    for(int j = 1; j <= n; ++j)
    {
        for(int k = 0; k <= 1; ++k)
        {
            f[1][j][k] = f[0][f[0][j][k]][1 - k];
        }
    }
    for(int i = 2; i < N; ++i)
    {
        for(int j = 1; j <= n; ++j)
        {
            for(int k = 0; k <= 1; ++k)
            {
                f[i][j][k] = f[i - 1][f[i - 1][j][k]][k];
            }
        }
    }
}

 

 da [i] [j] [ k]:都市jから始めて、kが最初に進み 2 ^ i 、ステップに戻り、少しAの距離を移動しました。

 db [i] [j] [ k]:都市jから始めて、kが最初に進み 2 ^ i 、ステップに戻り、小さなB距離が移動しました。 

まず、関数get_dist(i、j)= abs(h [i] -h [j]);を定義します。

i = 0:da [0] [j] [0] = get_dist(j、ga [j])、da [0] [j] [1] = 0;

           db [0] [j] [0] = 0、db [0] [j] [1] = get_dist(j、gb [j]);

i = 1:はい[1] [j] [k] =はい[0] [j] [k] +はい[0] [f [0] [j] [k]] [1-k];

          db [1] [j] [k] = db [0] [j] [k] + db [0] [f [0] [j] [k]] [1-k];

i> 1:はい[i] [j] [k] =はい[i-1] [j] [k] +はい[i-1] [f [i-1] [j] [k]] [k ];

          db [i] [j] [k] = db [i-1] [j] [k] + db [i-1] [f [i-1] [j] [k]] [k];

int get_dist(int i, int j)
{
    return (int)abs(h[i] - h[j]);
}

void init_d()
{
    for(int j = 1; j <= n; ++j)
    {
        da[0][j][0] = get_dist(j, ga[j]), da[0][j][1] = 0;
        db[0][j][1] = 0, db[0][j][1] = get_dist(j, gb[j]);
    }
    for(int j = 1; j <= n; ++j)
    {
        for(int k = 0; k <= 1; ++k)
        {
            da[1][j][k] = da[0][j][k] + da[0][f[0][j][k]][1 - k];
            db[1][j][k] = db[0][j][k] + db[0][f[0][j][k]][1 - k];
        }
    }
    for(int i = 2; i < N; ++i)
    {
        for(int j = 1; j <= n; ++j)
        {
            for(int k = 0; k <= 1; ++k)
            {
                da[i][j][k] = da[i - 1][j][k] + da[i - 1][f[i - 1][j][k]][k];
                db[i][j][k] = db[i - 1][j][k] + db[i - 1][f[i - 1][j][k]][k];
            }
        }
    }
}

 

4.コードの実装:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int M = (int)1e5;
const int N = (int)17;
const ll inf = 0x3f3f3f3f3f3f3f3f;

int n;
int h[M + 5];
int ga[M + 5], gb[M + 5];
int f[N][M + 5][2];
ll da[N][M + 5][2], db[N][M + 5][2];

void read()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
        scanf("%d", &h[i]);
}

void init_g()
{
    set < pair <ll, int> > st;
    st.emplace(make_pair(inf, 0));
    st.emplace(make_pair(inf + 1, 0));
    st.emplace(make_pair(-inf, 0));
    st.emplace(make_pair(-inf - 1, 0));
    for(int i = n; i >= 1; --i)
    {
        auto j = st.lower_bound(make_pair(h[i], i));
        --j, --j;
        ll mn = inf, sm = inf;
        int mni, smi;
        for(int k = 0; k < 4; ++k)
        {
            auto p = *j;
            ll d = (ll)abs(p.first - h[i]);
            if(d < mn)
            {
                sm = mn, smi = mni;
                mn = d, mni = p.second;
            }
            else if(d < sm)
            {
                sm = d, smi = p.second;
            }
            ++j;
        }
        ga[i] = smi, gb[i] = mni;
        st.emplace(make_pair(h[i], i));
    }
}

void init_f()
{
    for(int j = 1; j <= n; ++j)
    {
        f[0][j][0] = ga[j];
        f[0][j][1] = gb[j];
    }
    for(int j = 1; j <= n; ++j)
    {
        for(int k = 0; k <= 1; ++k)
        {
            f[1][j][k] = f[0][f[0][j][k]][1 - k];
        }
    }
    for(int i = 2; i < N; ++i)
    {
        for(int j = 1; j <= n; ++j)
        {
            for(int k = 0; k <= 1; ++k)
            {
                f[i][j][k] = f[i - 1][f[i - 1][j][k]][k];
            }
        }
    }
}

int get_dist(int i, int j)
{
    return (int)abs(h[i] - h[j]);
}

void init_d()
{
    for(int j = 1; j <= n; ++j)
    {
        da[0][j][0] = get_dist(j, ga[j]), da[0][j][1] = 0;
        db[0][j][1] = 0, db[0][j][1] = get_dist(j, gb[j]);
    }
    for(int j = 1; j <= n; ++j)
    {
        for(int k = 0; k <= 1; ++k)
        {
            da[1][j][k] = da[0][j][k] + da[0][f[0][j][k]][1 - k];
            db[1][j][k] = db[0][j][k] + db[0][f[0][j][k]][1 - k];
        }
    }
    for(int i = 2; i < N; ++i)
    {
        for(int j = 1; j <= n; ++j)
        {
            for(int k = 0; k <= 1; ++k)
            {
                da[i][j][k] = da[i - 1][j][k] + da[i - 1][f[i - 1][j][k]][k];
                db[i][j][k] = db[i - 1][j][k] + db[i - 1][f[i - 1][j][k]][k];
            }
        }
    }
}

void init()
{
    init_g();
    init_f();
    init_d();
}

void cal(int s, int x, int& la, int& lb)
{
    la = lb = 0;
    for(int i = N - 1; i >= 0; --i)
    {
        if(f[i][s][0] && la + lb + da[i][s][0] + db[i][s][0] <= x)
        {
            la += da[i][s][0];
            lb += db[i][s][0];
            s = f[i][s][0];
        }
    }
}

void work()
{
    int s, x;
    scanf("%d", &x);
    int la, lb;
    int max_h = 0, ans;
    double min_r = inf, r;
    for(int i = 1; i <= n; ++i)
    {
        cal(i, x, la, lb);
        r = lb ? 1.0 * la / lb : inf;
        if(r < min_r || r == min_r && h[i] > max_h)
        {
            ans = i;
            min_r = r;
            max_h = h[i];
        }
    }
    printf("%d\n", ans);
    int m;
    scanf("%d", &m);
    while((m--) > 0)
    {
        scanf("%d %d", &s, &x);
        cal(s, x, la, lb);
        printf("%d %d\n", la, lb);
    }
}

int main()
{
//    freopen("input.txt", "r", stdin);
    read();
    init();
    work();
    return 0;
}

 

おすすめ

転載: blog.csdn.net/The___Flash/article/details/104135861