公式

G - Laser Marking 解説 by en_translator


Notice the very small constraints, \(N \le 6\).
They may allow us to brute force over all the ways to operate the laser.

Once we made our mind to do brute force, let us find the parameters to enumerate and fix them.

  • The order to draw lines: \(N!\) ways
  • The direction of drawing lines (from which to which?): \(2^N\) ways

For \(N = 6\), there are \(6! \times 2^6 = 46080\) ways in total, which we can exhaustively enumerate easily.

The orders of drawing lines can be covered by iterating all the length-\(N\) permutations.
One can use a recursive function, or conveniently use next_permutation in C++, to enumerate the permutations.permutations.permutations.permutations.

The directions of drawing lines can be covered by enumerating the integers from \(0\) through \(2^N-1\), determining that the line is draw in \((A_i,B_i) \rightarrow (C_i,D_i)\) direction if the \(i\)-th significant bit of the integer is \(0\), and vice versa.

Once the order and directions are fixed, the way to achieve it is immediately determined (it is optimal to move from the initial point or the end point of the last line segment to the starting point of the next segment).

Hence, double loop against these two parameters realize exhaustive search over the \(N! \times 2^N\) ways to operate the machine.

Sample code (C++):

#include<bits/stdc++.h>

using namespace std;
using pi=pair<int,int>;

long double dist(pi l,pi r){
  long long v=0;
  v+=(l.first-r.first)*(l.first-r.first);
  v+=(l.second-r.second)*(l.second-r.second);
  return sqrtl(((long double)v));
}

int main(){
  int n,s,t;
  cin >> n >> s >> t;
  vector<pi> x(n),y(n);
  for(int i=0;i<n;i++){
    cin >> x[i].first >> x[i].second >> y[i].first >> y[i].second;
  }

  long double res=8e18;
  vector<int> p;
  for(int i=0;i<n;i++){
    p.push_back(i);
  }

  do{
    for(int i=0;i<(1<<n);i++){
      long double cres=0.0;
      pi cur=make_pair(0,0);
      for(int j=0;j<n;j++){
        int el=p[j];
        if(i&(1<<j)){
          cres+=( dist(cur,x[el])/((long double)s) );
          cres+=( dist(x[el],y[el])/((long double)t) );
          cur=y[el];
        }
        else{
          cres+=( dist(cur,y[el])/((long double)s) );
          cres+=( dist(y[el],x[el])/((long double)t) );
          cur=x[el];
        }
      }
      res=min(res,cres);
    }
  }while(next_permutation(p.begin(),p.end()));

  cout << fixed << setprecision(12) << res << "\n";
  return 0;
}

投稿日時:
最終更新: