E - Booster Editorial by llichenyu


It’s a simple problem,we could use DP to solve it.

Let the status \(f_{i,j,k}\) be the minimum cost of the numbers in \(i\) and \(j\),and the last visited number is \(k\).

We could enumerate the last status and transfer that.

The details are in the code.

//A tree without skin will surely die. 
//A man without face is invincible.
#include<bits/stdc++.h>
using namespace std;
#define int long long
double f[1<<13][1<<6][19];
int x[20],y[20],p[20],q[20];
inline int popcnt(int x){int sum=0;while (x) ++sum,x-=(x&-x);return sum;}
inline double dis(int i,int j){return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));}
inline int qpow(int a,int b){int ans=1;while (b){if (b&1) ans*=a;a*=a;b>>=1;}return ans;}
signed main(){
    ios::sync_with_stdio(false);
    cout.tie(0),cout.tie(0);
    int n,m;cin>>n>>m;
    x[0]=y[0]=0;
    for (int i=1;i<=n;++i) cin>>x[i]>>y[i];
    ++n;
    for (int i=0;i<m;++i) cin>>p[i]>>q[i],x[i+n]=p[i],y[i+n]=q[i];
    for (int i=0;i<(1<<n);++i)
        for (int j=0;j<(1<<m);++j)
            for (int l=0;l<n+m;++l)
                f[i][j][l]=9e18;
    f[1][0][0]=0;
    for (int i=0;i<(1<<n);++i)
        for (int j=0;j<(1<<m);++j){
            for (int l=0;l<n+m;++l){
                if ((l<n && !(i&(1<<l))) || (l>n && !(j&(1<<(l-n))))) continue;
                int speed=qpow(2,popcnt(j));
                for (int k=0;k<n;++k){
                    if (!(i&(1<<k))) continue;
                    if (k==l) continue;
                    if (l<n)
                        f[i][j][l]=min(f[i][j][l],dis(l,k)/speed+f[i^(1<<l)][j][k]);
                    else
                        f[i][j][l]=min(f[i][j][l],dis(l,k)/(speed/2)+f[i][j^(1<<(l-n))][k]);
                }
                for (int k=0;k<m;++k){
                    if (!(j&(1<<k))) continue;
                    if (l<n)
                        f[i][j][l]=min(f[i][j][l],dis(l,n+k)/speed+f[i^(1<<l)][j][n+k]);
                    else
                        f[i][j][l]=min(f[i][j][l],dis(l,n+k)/(speed/2)+f[i][j^(1<<(l-n))][n+k]);
                }
            }
        }
    double ans=9e18;
    for (int j=0;j<(1<<m);++j)
        for (int l=0;l<n+m;++l)
            ans=min(ans,f[(1<<n)-1][j][l]+dis(0,l)/qpow(2,popcnt(j )));
    cout<<fixed<<setprecision(10)<<ans<<'\n';
    return 0;
}

posted:
last update: