Advertisement
Guest User

Untitled

a guest
Apr 25th, 2017
105
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include "trace.h"
  2. #include "timer.h"
  3. #include <string>
  4. #include <vector>
  5. #include <cassert>
  6. #include <sstream>
  7. #include <algorithm>
  8. #include <numeric>
  9. #include <unordered_set>
  10. #include <set>
  11. #include <time.h>
  12. #include <random>
  13.  
  14.  
  15. // These three constants are adjustable
  16. const bool DO_MAX = true;
  17. const int N_ = 17;
  18. const int MARGIN = 1; // how much half-area away from theoretical optimal will you tolerate?
  19. const int HULL_SIZE = 4; // used for "max" only
  20.  
  21. const int N = N_ - ( DO_MAX ? HULL_SIZE : 0 );
  22. static int g_BEST = (DO_MAX ? HULL_SIZE == 3 ? N-1 : N : N-2 ) + MARGIN;
  23.  
  24. using namespace std;
  25.  
  26. static string searchName()
  27. {
  28. stringstream ss;
  29. ss << N_;
  30. ss << (DO_MAX ? "max" : "min");
  31. if ( DO_MAX )
  32. ss << " hull" << HULL_SIZE;
  33. return ss.str();
  34. }
  35.  
  36. class XY
  37. {
  38. public:
  39. XY( int px, int py ) { set( px, py ); }
  40. XY() { set(0, 0); }
  41. ~XY() {}
  42. void set( int px, int py ) { x = px; y = py; }
  43.  
  44. int len2() const { return x*x + y*y; }
  45. int dist2( const XY& p ) const { return (p.x-x)*(p.x-x) + (p.y-y)*(p.y-y); }
  46. XY transposed() const { return XY( y, x ); }
  47.  
  48. XY operator-() const { return XY( -x, -y ); }
  49. XY operator-( const XY& p ) const { return XY( x - p.x, y - p.y ); }
  50. XY operator+( const XY& p ) const { return XY( x + p.x, y + p.y ); }
  51. XY operator*( int iMul ) const { return XY(x * iMul, y * iMul); }
  52. XY operator/( int iDiv ) const { return XY(x / iDiv, y / iDiv); }
  53. const XY& operator-=( const XY& p ) { return *this = *this - p; }
  54. const XY& operator+=( const XY& p ) { return *this = *this + p; }
  55. const XY& operator*=( int iMul ) { return *this = *this * iMul; }
  56. const XY& operator/=( int iDiv ) { return *this = *this / iDiv; }
  57.  
  58. int operator^( const XY& p ) const { return x*p.y - y*p.x; }
  59. int operator*( const XY& p ) const { return x*p.x + y*p.y; }
  60.  
  61. bool operator==( const XY& p ) const { return x == p.x && y == p.y; }
  62. bool operator!=( const XY& p ) const { return !(*this == p); }
  63. bool operator<( const XY& p ) const { return (y != p.y) ? (y < p.y) : (x < p.x); }
  64.  
  65. static XY dir( int x ) { static XY a[] = { XY(1,0), XY(0,1), XY(-1,0), XY(0,-1) }; return a[x]; }
  66.  
  67. public:
  68. int x, y;
  69. };
  70.  
  71. int doubleArea( const vector<XY>& v )
  72. {
  73. int ret = v.empty() ? 0 : v.back()^v[0];
  74. for ( int i = 0; i+1 < (int) v.size(); i++ )
  75. ret += v[i]^v[i+1];
  76. return abs(ret);
  77. }
  78.  
  79. bool intersects( int a, int b, int u, int v )
  80. {
  81. return max( a, b ) >= min( u, v )
  82. && min( a, b ) <= max( u, v );
  83. }
  84.  
  85. // assumes different slopes
  86. bool intersects( const XY& a, const XY& b, const XY& u, const XY& v )
  87. {
  88. //int num0 = (u-a)^(v-u);
  89. //int den0 = (b-a)^(v-u);
  90. //int num1 = (a-u)^(b-a);
  91. //int den1 = (v-u)^(b-a);
  92.  
  93. //if ( den0 < 0 ) { num0 = -num0; den0 = -den0; }
  94. //if ( den1 < 0 ) { num1 = -num1; den1 = -den1; }
  95. //return num0 >= 0 && num0 <= den0
  96. // && num1 >= 0 && num1 <= den1;
  97. assert( a != b );
  98. assert( u != v );
  99.  
  100. int num0 = (u-a)^(v-u);
  101. int den0 = (b-a)^(v-u);
  102. int num1 = (u-a)^(b-a);
  103.  
  104. if ( den0 == 0 ) // same slope
  105. {
  106. //return false;
  107. if ( num0 != 0 ) return false; // parallel, but not colinear
  108. return a.x != b.x ? intersects( a.x, b.x, u.x, v.x ) : intersects( a.y, b.y, u.y, v.y );
  109. }
  110.  
  111. if ( den0 < 0 ) { num0 = -num0; num1 = -num1; den0 = -den0; }
  112. return num0 >= 0 && num0 <= den0
  113. && num1 >= 0 && num1 <= den0;
  114. }
  115. bool isClockwise( const XY& a, const XY& b, const XY& c ) { return ((a-b)^(c-b)) < 0; }
  116. bool isClockwiseOrColinear( const XY& a, const XY& b, const XY& c ) { return ((a-b)^(c-b)) <= 0; }
  117. bool isInOrOnClockwiseTriangle( const XY& a, const XY& b, const XY& c, const XY& p )
  118. {
  119. return isClockwiseOrColinear( a,b,p )
  120. && isClockwiseOrColinear( b,c,p )
  121. && isClockwiseOrColinear( c,a,p );
  122. }
  123.  
  124. int gcd( int a, int b ) { return a ? gcd( b%a, a ) : b; }
  125. int gcd( const XY& pt ) { return gcd( abs(pt.x), abs(pt.y) ); }
  126.  
  127. string str( const XY& p )
  128. {
  129. stringstream ss;
  130. ss << "(" << p.x << "," << p.y << ")";
  131. return ss.str();
  132. }
  133. string str( const vector<XY>& v, int offset )
  134. {
  135. stringstream ss;
  136. for ( int i = 0; i < (int) v.size(); i++ )
  137. ss << (i ? "," : "") << str( v[i] + XY(offset,offset) );
  138. return ss.str();
  139. }
  140.  
  141. template<int N>
  142. class SlopeInfo
  143. {
  144. public:
  145. SlopeInfo()
  146. {
  147. memset( m, -1, sizeof( m ) );
  148. m[0][0] = 0;
  149. XY p;
  150. for ( p.y = 0; p.y < N; p.y++ )
  151. for ( p.x = 0; p.x < N; p.x++ )
  152. {
  153. if ( m[p.y][p.x] >= 0 ) continue;
  154. for ( XY q = p; q.x < N && q.y < N; q += p )
  155. m[q.y][q.x] = _NumIds;
  156. _NumIds++;
  157. }
  158. _NumSlopes = _NumIds * 2 - 2;
  159. }
  160. static const SlopeInfo& TheInstance()
  161. {
  162. static SlopeInfo s_theInstance;
  163. return s_theInstance;
  164. }
  165. int IdOf_( XY p ) const
  166. {
  167. if ( p.y == 0 ) return 0;
  168. if ( p.y < 0 ) p = -p;
  169. return p.x > 0 ? m[p.y][p.x] : m[p.y][-p.x] + _NumIds-2;
  170. }
  171. static int IdOf( const XY& p )
  172. {
  173. return TheInstance().IdOf_( p );
  174. }
  175. static int NumUniqueSlopes() { return TheInstance()._NumSlopes; }
  176.  
  177. public:
  178. int m[N][N];
  179. int _NumIds;
  180. int _NumSlopes;
  181. };
  182.  
  183. template<int N>
  184. class SlopeInfoSym
  185. {
  186. public:
  187. SlopeInfoSym()
  188. {
  189. memset( m, -1, sizeof( m ) );
  190. m[0][0] = 0;
  191. XY p;
  192. for ( p.y = 0; p.y < N; p.y++ )
  193. for ( p.x = 0; p.x < N; p.x++ )
  194. {
  195. if ( m[p.y][p.x] >= 0 ) continue;
  196. for ( XY q = p; q.x < N && q.y < N; q += p )
  197. m[q.y][q.x] = m[q.x][q.y] = _NumIds;
  198. _NumIds++;
  199. }
  200. _NumSlopes = _NumIds * 2 - 1;
  201. }
  202. static const SlopeInfoSym& TheInstance()
  203. {
  204. static SlopeInfoSym s_theInstance;
  205. return s_theInstance;
  206. }
  207. int IdOf_( XY p ) const
  208. {
  209. if ( p.y == 0 ) return 0;
  210. if ( p.y < 0 ) p = -p;
  211. return p.x > 0 ? m[p.y][p.x] : m[p.y][-p.x] + _NumIds-1;
  212. }
  213. static int IdOf( XY p )
  214. {
  215. return TheInstance().IdOf_( p );
  216. }
  217. static int NumUniqueSlopes() { return TheInstance()._NumSlopes; }
  218.  
  219. public:
  220. int m[N][N];
  221. int _NumIds;
  222. int _NumSlopes;
  223. };
  224.  
  225.  
  226. struct LatticeLineSegment
  227. {
  228. XY pt0;
  229. XY dir;
  230. int n;
  231.  
  232. XY pt( int i ) const { return pt0 + dir * i; }
  233. std::vector<XY> allPoints() const { std::vector<XY> v; for ( int i = 0; i < n; i++ ) v.push_back( pt( i ) ); return v; }
  234. std::set<XY> allPointsSet() const { std::vector<XY> v = allPoints(); return std::set<XY>( v.begin(), v.end() ); }
  235. static LatticeLineSegment emptySet() { return LatticeLineSegment{ XY(), XY(), 0 }; }
  236. };
  237.  
  238. // ax + by = c
  239. LatticeLineSegment findLatticePointsOnLine( int a, int b, int c, int lo, int hi )
  240. {
  241. assert( a != 0 && b != 0 );
  242. if ( abs( gcd( a, b ) ) != 1 )
  243. return LatticeLineSegment::emptySet();
  244. // ax + by = c (mod b)
  245. // ax = c (mod b)
  246. XY pt0;
  247. for ( pt0.x = lo; ( c - a * pt0.x ) % b; pt0.x++ );
  248. pt0.y = (c - a * pt0.x) / b;
  249.  
  250. XY dir = XY( b, -a );
  251.  
  252. // the line: pt0 + dir * t
  253. // on x-axis: lo <= pt0.x + dir.x * t pt0.x + dir.x * t < hi
  254. // (lo - pt0.x) / dir.x <= t t < (hi - pt0.x) / dir.x (for reals) (for positive dir.x)
  255. // (lo - pt0.x + dir.x-1) / dir.x <= t t < (hi - pt0.x + dir.x - 1) / dir.x (for integers)
  256.  
  257. // (lo - pt0.x) / dir.x >= t t > (hi - pt0.x) / dir.x (for reals) (for negative dir.x)
  258. // (lo - pt0.x) / dir.x >= t t > (hi - pt0.x) / dir.x (for integers)
  259. // (hi - pt0.x) / dir.x < t t <= (lo - pt0.x) / dir.x (for integers)
  260. // (hi - pt0.x) / dir.x + 1 <= t t < (lo - pt0.x) / dir.x + 1 (for integers)
  261.  
  262. // 1024 to make division always do floor
  263. int tlo_x = ( dir.x >= 0 ? (lo - pt0.x + dir.x-1 + dir.x*1024) / dir.x : (hi - pt0.x + dir.x*1024) / dir.x + 1 ) - 1024;
  264. int thi_x = ( dir.x >= 0 ? (hi - pt0.x + dir.x-1 + dir.x*1024) / dir.x : (lo - pt0.x + dir.x*1024) / dir.x + 1 ) - 1024;
  265. int tlo_y = ( dir.y >= 0 ? (lo - pt0.y + dir.y-1 + dir.y*1024) / dir.y : (hi - pt0.y + dir.y*1024) / dir.y + 1 ) - 1024;
  266. int thi_y = ( dir.y >= 0 ? (hi - pt0.y + dir.y-1 + dir.y*1024) / dir.y : (lo - pt0.y + dir.y*1024) / dir.y + 1 ) - 1024;
  267. int tlo = max( tlo_x, tlo_y );
  268. int thi = min( thi_x, thi_y );
  269. return { pt0 + dir*tlo, dir, max( thi - tlo, 0 ) };
  270. }
  271.  
  272.  
  273. namespace Shards
  274. {
  275.  
  276. class Poly
  277. {
  278. public:
  279. Poly()
  280. {
  281. _NumCommittedEdges = 0;
  282. _UsedX = 0;
  283. _UsedY = 0;
  284. _DoubledArea = 0;
  285. memset( _UsedSlope, 0, sizeof( _UsedSlope ) );
  286. }
  287.  
  288. int NewAreaFor( const XY& pt ) const { return v.size() >= 3 ? abs((v[_NumCommittedEdges]-pt)^(v[_NumCommittedEdges+1]-pt)) : 0; }
  289. int MinimumAreaWith( const XY& pt ) const { return _DoubledArea + NewAreaFor( pt ) + (N-1-NumPoints()); }
  290. int MinimumArea() const { return _DoubledArea + (N-NumPoints()); }
  291. bool IsSideways( const XY& pt ) const
  292. {
  293. bool s0 = (pt.x > v[_NumCommittedEdges].x) != (pt.y > v[_NumCommittedEdges].y);
  294. bool s1 = (pt.x > v[_NumCommittedEdges+1].x) != (pt.y > v[_NumCommittedEdges+1].y);
  295. return s0 && s1;
  296. }
  297.  
  298. bool IsClosed() const { return _NumCommittedEdges + 1 >= (int) v.size() && (int) v.size() > 3; }
  299.  
  300. bool AddPoint( const XY& pt )
  301. {
  302. if ( IsClosed() )
  303. return false; // all edges are committed, can't add anything more!
  304.  
  305. if ( _UsedX & (1LL << pt.x) ) return false;
  306. if ( _UsedY & (1LL << pt.y) ) return false;
  307.  
  308. if ( v.size() >= 3 )
  309. {
  310. if ( !isClockwise( v[_NumCommittedEdges], pt, v[_NumCommittedEdges+1] ) ) return false;
  311.  
  312. // test first new edge
  313. for ( int i = 0; i+1 < (int) v.size(); i++ ) if ( i != _NumCommittedEdges && i+1 != _NumCommittedEdges )
  314. if ( intersects( v[i], v[i+1], v[_NumCommittedEdges], pt ) )
  315. return false;
  316. // test second new edge
  317. for ( int i = 1; i+1 < (int) v.size(); i++ ) if ( i != (_NumCommittedEdges+1)%(v.size()-1) && i+1 != _NumCommittedEdges+1 )
  318. if ( intersects( v[i], v[i+1], pt, v[_NumCommittedEdges+1] ) )
  319. return false;
  320.  
  321. _DoubledArea += NewAreaFor( pt );
  322. }
  323.  
  324.  
  325. // TODO: assert( make sure polygon isn't goofy ) ??
  326.  
  327. _UsedX |= 1LL << pt.x;
  328. _UsedY |= 1LL << pt.y;
  329.  
  330. if ( v.empty() )
  331. v.push_back( pt );
  332. v.insert( v.begin() + _NumCommittedEdges + 1, pt );
  333.  
  334. return true;
  335. }
  336.  
  337. void RemoveLast()
  338. {
  339. XY pt = v[_NumCommittedEdges + 1];
  340. assert( _UsedX & (1LL << pt.x) );
  341. assert( _UsedY & (1LL << pt.y) );
  342. _UsedX &= ~(1LL << pt.x);
  343. _UsedY &= ~(1LL << pt.y);
  344. v.erase( v.begin() + _NumCommittedEdges + 1 );
  345. if ( v.size() >= 3 )
  346. _DoubledArea -= NewAreaFor( pt );
  347.  
  348. if ( v.size() == 1 ) v.pop_back(); // first point was duplicated at the end
  349. }
  350.  
  351. // say we've committed two edges, and we're adding a new point 'p'
  352. // The new point creates triangle <2,p,3>
  353. // But if we can remove <1,2,3> and add <1,p,3> and <1,2,p> would give same polygon (with one less committed edge)
  354. bool IsRedundant( const XY& p ) const
  355. {
  356. if ( _NumCommittedEdges <= 0 ) return false;
  357. const XY& v1 = v[_NumCommittedEdges-1];
  358. const XY& v2 = v[_NumCommittedEdges];
  359. const XY& v3 = v[_NumCommittedEdges+1];
  360. if ( !isClockwise( v2, p, v3 ) ) return false;
  361. if ( !isClockwise( v1, v2, p ) ) return false;
  362. if ( !isClockwise( v1, p, v3 ) ) return false;
  363. if ( !isClockwise( v1, v2, v3 ) ) return false;
  364.  
  365. // can remove <1,2,3>? yes, if no vertices are inside
  366. for ( int i = 0; i < _NumCommittedEdges - 1; i++ )
  367. if ( isInOrOnClockwiseTriangle( v1, v2, v3, v[i] ) )
  368. return false;
  369. for ( int i = _NumCommittedEdges+2; i < (int)v.size(); i++ )
  370. if ( isInOrOnClockwiseTriangle( v1, v2, v3, v[i] ) )
  371. return false;
  372.  
  373. return true;
  374. }
  375.  
  376.  
  377. bool CommittingWouldClose() const { return _NumCommittedEdges+2 >= (int) v.size(); }
  378. bool CanClose() const { return NumPoints() == N || !CommittingWouldClose(); }
  379.  
  380. bool CommitEdge()
  381. {
  382. if ( !CanClose() )
  383. return false;
  384. if ( _NumCommittedEdges+1 >= (int) v.size() )
  385. return false;
  386. int slopeId = SlopeInfo<N>::IdOf( v[_NumCommittedEdges+1] - v[_NumCommittedEdges] );
  387. if ( _UsedSlope[slopeId] )
  388. return false;
  389.  
  390. _NumCommittedEdges++;
  391. _UsedSlope[slopeId] = true;
  392.  
  393. return true;
  394. }
  395. void UnCommitEdge()
  396. {
  397. _NumCommittedEdges--;
  398. int slopeId = SlopeInfo<N>::IdOf( v[_NumCommittedEdges+1] - v[_NumCommittedEdges] );
  399. assert( _UsedSlope[slopeId] );
  400. _UsedSlope[slopeId] = false;
  401. }
  402. int NumPoints() const { return v.size() == 0 ? 0 : (int)v.size() - 1; }
  403.  
  404. vector<XY> pointsWithHull() const
  405. {
  406. const XY offset = HULL_SIZE == 3 ? XY( 2, 2 ) : XY( 2, 2 );
  407.  
  408. vector<XY> ret;
  409. for ( int i = 1; i < (int) v.size()-1; i++ )
  410. ret.push_back( v[i] + offset );
  411. ret.push_back( v[0] + offset );
  412.  
  413. if ( HULL_SIZE == 3 )
  414. {
  415. ret.push_back( XY(1,N+2) );
  416. ret.push_back( XY(N+3,N+3) );
  417. ret.push_back( XY(N+2,1) );
  418. }
  419. else
  420. {
  421. ret.push_back( XY(1,N+3) );
  422. ret.push_back( XY(N+2,N+4) );
  423. ret.push_back( XY(N+4,N+2) );
  424. ret.push_back( XY(N+3,1) );
  425. }
  426. return ret;
  427. }
  428.  
  429. double Area() const { return doubleArea( DO_MAX ? pointsWithHull() : v ) / 2.; }
  430.  
  431. string Str() const
  432. {
  433. stringstream ss;
  434. if ( DO_MAX && v.size()-1 == N )
  435. {
  436. ss << str( pointsWithHull(), 0 );
  437. }
  438. else
  439. {
  440. ss << str( v, 1 );
  441. }
  442. return ss.str();
  443. }
  444.  
  445. uint64_t HashCode() const
  446. {
  447.  
  448. }
  449.  
  450. public:
  451. vector<XY> v;
  452. char _UsedSlope[N*N*2];
  453. uint64_t _UsedX;
  454. uint64_t _UsedY;
  455. int _NumCommittedEdges;
  456. int _DoubledArea;
  457. };
  458.  
  459. class Searcher
  460. {
  461. public:
  462. Searcher()
  463. {
  464. _NumNodes.resize(N+2);
  465. if ( DO_MAX )
  466. {
  467. _Poly.AddPoint( XY( 0, 1 ) );
  468. _Poly.AddPoint( XY( 1, 0 ) );
  469. _Poly.CommitEdge();
  470. Go();
  471. }
  472. else
  473. {
  474. XY p0 = XY( 0, 0 );
  475. for ( p0.y = 0; p0.y <= N/2; p0.y++ )
  476. {
  477. if ( !_Poly.AddPoint( p0 ) ) continue;
  478. XY p1;
  479. for ( p1.x = 0; p1.x < N; p1.x++ )
  480. for ( p1.y = 0; p1.y < N; p1.y++ )
  481. {
  482. //if ( p0.x == p0.y && p1.x > p1.y ) continue; //clockwise/counter-clockwise matters
  483. if ( abs( gcd( p1.x - p0.x, p1.y - p0.y ) ) != 1 ) continue;
  484. if ( !_Poly.AddPoint( p1 ) ) continue;
  485. if ( _Poly.CommitEdge() )
  486. {
  487. //trace << _Poly.Str() << "..." << endl;
  488. Go();
  489. _Poly.UnCommitEdge();
  490. }
  491. _Poly.RemoveLast();
  492. }
  493. _Poly.RemoveLast();
  494. }
  495. }
  496.  
  497. //trace << "nodesAtEachDepth[] = " << vstr( _NumNodes ) << endl;
  498. trace << "#nodes = " << accumulate(_NumNodes.begin(), _NumNodes.end(), 0LL) << endl;
  499. }
  500.  
  501. void Go()
  502. {
  503. _NumNodes[_Poly.v.size()]++;
  504.  
  505. if ( _Poly.IsClosed() )
  506. {
  507. assert( _Poly.NumPoints() == N );
  508. stringstream ss;
  509. ss << "### " << searchName() << " " << _Poly.Area() << " " << _Poly.Str() << endl;
  510. static set<string> s_printed;
  511. if ( s_printed.count( ss.str() ) )
  512. return;
  513. s_printed.insert( ss.str() );
  514. trace << ss.str();
  515. if ( _Poly._DoubledArea < g_BEST )
  516. g_BEST = _Poly._DoubledArea;
  517. return;
  518. }
  519.  
  520. if ( _Poly.CommitEdge() )
  521. {
  522. Go();
  523. _Poly.UnCommitEdge();
  524. }
  525.  
  526. if ( _Poly.NumPoints() == N ) return;
  527.  
  528. if ( _Poly.MinimumArea() == g_BEST ) // optimization (optional)
  529. {
  530. XY a = _Poly.v[_Poly._NumCommittedEdges];
  531. XY b = _Poly.v[_Poly._NumCommittedEdges+1];
  532. LatticeLineSegment seg = findLatticePointsOnLine( b.y-a.y, a.x-b.x, 1+a.x*(b.y-a.y)-a.y*(b.x-a.x), 0, N );
  533. XY p = seg.pt0;
  534. for ( int i = 0; i < seg.n; i++, p += seg.dir )
  535. {
  536. //if ( abs((p.x-p.y)-(a.x-a.y)) > 2 && abs((p.x-p.y)-(b.x-b.y)) > 2 ) continue;
  537. //if ( !( abs((a.x-a.y) - (p.x-p.y)) <= 1 || abs((b.x-b.y) - (p.x-p.y)) <= 1 ) ) continue;
  538. assert( _Poly.NewAreaFor( p ) == 1 );
  539. if ( _Poly._UsedY & (1LL << p.y) ) continue;
  540. if ( _Poly._UsedX & (1LL << p.x) ) continue;
  541. if ( _Poly.IsRedundant( p ) ) continue;
  542. if ( !_Poly.AddPoint( p ) ) continue;
  543. Go();
  544. _Poly.RemoveLast();
  545. }
  546. }
  547. else
  548. {
  549. XY p;
  550. for ( p.y = 0; p.y < N; p.y++ ) if ( !( _Poly._UsedY & (1LL << p.y) ) )
  551. for ( p.x = 0; p.x < N; p.x++ ) if ( !( _Poly._UsedX & (1LL << p.x) ) )
  552. {
  553. if ( _Poly.MinimumAreaWith( p ) > g_BEST ) continue;
  554. if ( _Poly.IsRedundant( p ) ) continue;
  555. if ( !_Poly.AddPoint( p ) ) continue;
  556.  
  557. Go();
  558.  
  559. _Poly.RemoveLast();
  560. }
  561. }
  562. }
  563.  
  564. public:
  565. Poly _Poly;
  566. vector<int64_t> _NumNodes;
  567. };
  568.  
  569. }
  570.  
  571. void main()
  572. {
  573. Timer t;
  574. Shards::Searcher searcher;
  575. trace << "Time = " << t.ElapsedTime() << " " << searchName() << " BEST=" << g_BEST << endl;
  576. }
Advertisement
RAW Paste Data Copied
Advertisement