[ABC274E] Booster 题解

[ABC274E] Booster Solution

更好的阅读体验戳此进入

题面

在经典的 TSP 问题基础上存在初始速度 $ 1 $,增加 $ m $ 个补给点,经过后会使速度变为原来的 $ 2 $ 倍,最小化时间,求最小值。

Solution

提供一个不太需要动脑但码量略大的思路。

考虑令 $ dp(i, j, k) $ 表示二进制下城镇状态为 $ i $,补给点状态为 $ j $,最后位于点 $ k $ 的最小时间,转移的时候枚举 $ i, j, k $ 再枚举从哪个点而来即可,需要分类讨论从普通点转移还是补给点,以及转移到了普通点还是补给点,对于速率直接使用 __builtin_popcount(j) 计算即可。

同时需要注意计算过程中最多只能使用 long double,使用 __float128 的话会存在约 $ 40 $ 倍常数导致 $ \texttt{TLE} $。

Code

#define _USE_MATH_DEFINES
#include <bits/stdc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW void* Edge::operator new(size_t){static Edge* P = ed; return P++;}
#define ROPNEW_NODE void* Node::operator new(size_t){static Node* P = nd; return P++;}

using namespace std;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

#define INFLD (ld)(1e12)

template < typename T = int >
inline T read(void);

int N, M;
pair < ll, ll > town[15], sup[8];
ld dp[4500][40][18];
ld ans(INFLD);

ld CalDis(pair < ll, ll > A, pair < ll, ll > B){
    return sqrt((ld)((A.first - B.first) * (A.first - B.first) + (A.second - B.second) * (A.second - B.second)));
}

int main(){
    for(int i = 0; i <= 4400; ++i)for(int j = 0; j <= 38; ++j)for(int k = 0; k <= 17; ++k)dp[i][j][k] = INFLD;
    N = read(), M = read();
    for(int i = 1; i <= N; ++i)town[i].first = read(), town[i].second = read();
    for(int i = 1; i <= M; ++i)sup[i].first = read(), sup[i].second = read();
    dp[0][0][0] = 0;
    int SmxN = (1 << N) - 1, SmxM = (1 << M) - 1;
    for(int i = 0; i <= SmxN; ++i)
        for(int j = 0; j <= SmxM; ++j){
            ll rate = 1 << __builtin_popcount(j);
            for(int k = 1; k <= N; ++k)
                if(!(i & (1 << (k - 1)))){
                    for(int pos = 0; pos <= N; ++pos)
                        if(dp[i][j][pos] < INFLD)
                            dp[i | (1 << (k - 1))][j][k] = min(dp[i | (1 << (k - 1))][j][k], dp[i][j][pos] + CalDis(town[pos], town[k]) / (ld)rate);
                    for(int pos = N + 1; pos <= N + M; ++pos)
                        if(dp[i][j][pos] < INFLD)
                            dp[i | (1 << (k - 1))][j][k] = min(dp[i | (1 << (k - 1))][j][k], dp[i][j][pos] + CalDis(sup[pos - N], town[k]) / (ld)rate);
                }
            for(int k = 1; k <= M; ++k)
                if(!(j & (1 << (k - 1)))){
                    for(int pos = 0; pos <= N; ++pos)
                        if(dp[i][j][pos] < INFLD)
                            dp[i][j | (1 << (k - 1))][N + k] = min(dp[i][j | (1 << (k - 1))][N + k], dp[i][j][pos] + CalDis(town[pos], sup[k]) / (ld)rate);
                    for(int pos = N + 1; pos <= N + M; ++pos)
                        if(dp[i][j][pos] < INFLD)
                            dp[i][j | (1 << (k - 1))][N + k] = min(dp[i][j | (1 << (k - 1))][N + k], dp[i][j][pos] + CalDis(sup[pos - N], sup[k]) / (ld)rate);
                }
        }
    for(int j = 0; j <= SmxM; ++j){
        ll rate = 1 << __builtin_popcount(j);
        for(int k = 1; k <= N + M; ++k)
            if(dp[SmxN][j][k] < INFLD)
                ans = min(ans, dp[SmxN][j][k] + CalDis(k <= N ? town[k] : sup[k - N], town[0]) / (ld)rate);
    }printf("%.8Lf\n", ans);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    int flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

UPD

update-2023_02_28 初稿

posted @ 2023-03-05 12:49  Tsawke  阅读(11)  评论(0编辑  收藏  举报