2117-Connect Line Segments
問題概要
n(<=14)個の線分が与えられる.
これらの線分全てを通るように折れ線の一筆書を構築する(詳しくは問題文の図を参照)
最短の長さを求めよ.
解法
現在使った線分と現在居る点をもとにビットDP(メモ化再帰)する.
計算量は2^n*n^2ぐらい
実装(C++)
#include <iostream> #include <algorithm> #include <complex> #include <vector> #include <cstdio> #include <iomanip> using namespace std; const double EPS=1e-7; const double INF=1e10; typedef complex<double> Point; inline double cross(const Point &a,const Point &b){return imag(conj(a)*b);} inline double dot(const Point &a,const Point &b){return real(conj(a)*b);} inline double atan(const Point &a){return atan2(imag(a),real(a));} namespace std{ bool operator<(const Point &a,const Point &b){return real(a)==real(b)?imag(a)<imag(b):real(a)<real(b);} Point operator*(const Point &a,const double &b){return Point(real(a)*b,imag(a)*b);} } struct Line:vector<Point>{ Line(double x1=0,double y1=0,double x2=0,double y2=0){ (*this).push_back(Point(x1,y1)); (*this).push_back(Point(x2,y2)); } Line(Point a,Point b){ (*this).push_back(a);(*this).push_back(b); } Point vector(){ return at(1)-at(0); } }; inline double abs(const Line &a){ return abs(a[1]-a[0]); } struct Circle{ Circle(Point center,double radius):c(center),r(radius){}; Circle(double x=0,double y=0,double r=0){(*this)=Circle(Point(x,y),r);} Point c;double r; }; typedef vector<Point> Polygon; Line getside(const Polygon& p,int no){ return Line(p[no],p[(no+1)%p.size()]); } #define TYPE(now) [now/2][now%2] Line pts[16]; double dp[1<<14][28]; int n; double solve(int bit,int now){ if(bit==(1<<n)-1)return 0; double &res=dp[bit][now]; if(res==-1){ res=1e9; for(int i=0;i<n;i++){ if((bit>>i)&1)continue; res=min(res,solve(bit|(1<<i),i*2)+abs(pts TYPE(now)-pts[i][1])); res=min(res,solve(bit|(1<<i),i*2+1)+abs(pts TYPE(now)-pts[i][0])); } } return res; } int main() { int T=1; for(;cin>>n;){ if(n==0)break; for(int i=0;i<n;i++)for(int j=0;j<2;j++)cin>>pts[i][j].real()>>pts[i][j].imag(); for(int i=0;i<(1<<n);i++)for(int j=0;j<n*2;j++)dp[i][j]=-1; double ans=1e9; double pans=0; for(int i=0;i<n;i++)pans+=abs(pts[i]); for(int i=0;i<2*n;i++){ ans=min(ans,solve(1<<(i/2),i)); } printf("Case %d: %.5f\n",T++,ans+pans); } return 0; }