USACO Feed Ratios, Magic Squares

本质上讲,这两道题都是数学题,ratios是行列式解线性方程组,squares是组合数学。可见ACMer数学基础好确实是非常重要的。

1、Feed Ratios

所求的实际上就是一个最简配比 x, y, z, w,使得 x(a1,b1,c1) + y(a2,b2,c2) + z(a3,b3,c3) = w(g1,g2,g3),我线性代数也忘得差不多了,不过对克莱姆法则还有一点印象。


  1. /*
  2. ID:fairyroad
  3. LANG:C++
  4. TASK:ratios
  5. */
  6.  
  7. #include
  8. using  namespace std ;
  9.  
  10. ifstream fin ( "ratios.in" ) ;
  11. ofstream fout ( "ratios.out" ) ;
  12.  
  13. const  int LEN  =  3 ;
  14. int dest [LEN ] ;
  15. int matrix [LEN ] [LEN ], backup [LEN ] [LEN ] ;
  16.  
  17. void cofactor ( const  int a [ ] [LEN ]int b [ ] [LEN ]int n,  int k )
  18. {
  19.      int bi  =  0, bj  =  0 ;
  20.      for ( int i  =  1 ; i  < n ;  ++i )
  21.      {
  22.          for ( int j  =  0 ; j  < n ;  ++j ) {
  23.              if (j ==k )
  24.              continue ;
  25.             b [bi ] [bj ]  = a [i ] [j ] ;
  26.             bj ++ ;
  27.          }
  28.         bi ++ ;
  29.         bj  =  0 ;
  30.      }
  31. }
  32.  
  33. int deter ( int a [ ] [LEN ]int n )
  34. {
  35.      if (n == 1 )
  36.      return a [ 0 ] [ 0 ] ;
  37.      else
  38.      {
  39.          int sum  =  0 ;
  40.          for ( int i  =  0 ; i  < n ;  ++i )
  41.          {
  42.              int b [LEN ] [LEN ]  =  { 0 } ;
  43.             cofactor (a,b,n,i ) ;
  44.              int coef  =  ( (i % 2 == 0 ) ? 1 : - 1 ) ;
  45.             sum  + =  (coef *a [ 0 ] [i ] *deter (b,n - 1 ) ) ;
  46.          }
  47.          return sum ;
  48.      }
  49. }
  50.  
  51. void change ( int curr,  int last  =  - 1 )
  52. {
  53.      if (last  ! =  - 1 )
  54.      {
  55.          for ( int i  =  0 ; i  < LEN ;  ++i )
  56.         matrix [last ] [i ]  = backup [last ] [i ] ;
  57.      }
  58.  
  59.      for ( int i  =  0 ; i  < LEN ;  ++i )
  60.     matrix [curr ] [i ]  = dest [i ] ;
  61. }
  62.  
  63. int gcd ( int m,  int n )
  64. {
  65.      if  (==  0 )  return n ;
  66.      if  (==  0 )  return m ;
  67.      if  (< n )
  68.      {
  69.          int tmp  = m ;
  70.         m  = n ;
  71.         n  = tmp ;
  72.      }
  73.      while  (! =  0 )
  74.      {
  75.          int tmp  = m  % n ;
  76.         m  = n ;
  77.         n  = tmp ;
  78.      }
  79.      return m ;
  80. }
  81.  
  82. int main ( )
  83. {
  84.      for ( int i  =  0 ; i  < LEN ; i ++ )
  85.         fin  >> dest [i ] ;
  86.  
  87.      int num ;
  88.      for ( int i  =  0 ; i  <  3 ; i ++ )
  89.      {
  90.          for ( int j  =  0 ; j  <  3 ; j ++ )
  91.          {
  92.             fin  >> num ;
  93.             matrix [i ] [j ]  = num, backup [i ] [j ]  = num ;
  94.          }
  95.      }
  96.  
  97.      int res1  = deter (matrix ,LEN ) ;
  98.      if (res1  ==  0 )  {
  99.         fout  <<  "NONE\n" ;
  100.          return  0 ;
  101.      }
  102.  
  103.     change ( 0- 1 ) ;
  104.      int res2  = deter (matrix, LEN ) ;
  105.  
  106.     change ( 10 ) ;
  107.      int res3  = deter (matrix, LEN ) ;
  108.  
  109.     change ( 21 ) ;
  110.      int res4  = deter (matrix, LEN ) ;
  111.  
  112.      if (res1  <  0 )
  113.      {
  114.         res1  =  -res1 ;
  115.         res2  =  -res2 ;
  116.         res3  =  -res3 ;
  117.         res4  =  -res4 ;
  118.      }
  119.  
  120.      if (res2  <  0  || res3  <  0  || res4  <  0 )
  121.      {
  122.         fout  <<  "NONE\n" ;
  123.          return  0 ;
  124.      }
  125.  
  126.      int tmp  = gcd (gcd (res2, gcd (res3, res4 ) ), res1 ) ;
  127.     fout  << res2 /tmp  <<  ' '  << res3 /tmp  <<  ' '  << res4 /tmp  <<  ' '  << res1 /tmp  <<  '\n' ;
  128.  
  129.      return  0 ;
  130. }

值得一提的是求解行列式的值,也是个比较好的递归的示例吧,我想大学里的《线性代数》课完全可以用编程来教嘛...


2、Magic Squares

这题还是蛮好的,整体思路要上考虑BFS,然后一个比较难的地方是设计一个好的HASH函数,因为BFS通常是很耗费空间的,要是HASH函数还没有比较好的空间利用率,可能会掉链子,当然这道题数据量不大,8位数码板,总共也就8! = 4W多种情况,但是你是程序员,多少得精益求精一点,所以,有了康托展开定理。

设Sn = {1,2,3,4,...,n}表示1,2,3,...,n的排列,如S3 = {1,2,3} 按从小到大排列一共6个 123 132 213 231 312 321。那么找出S5中45231在这个排列中所在的位置可以用下面的思路:

  1. 比4小的数有3个
  2. 比5小的数有4个但4已经在之前出现过了所以是3个
  3. 比2小的数有1个
  4. 比3小的数有两个但2已经在之前出现过了所以是1个
  5. 比1小的数有0个
  6. 那么45231在这个排列中的顺序是3*4!+3*3!+1*2!+1*1!+0*0!+1=94
空间还是可以的,时间表现一般吧,广搜是一般的思路,有谁能想出来启发式算法吗?


  1. /*
  2. ID:fairyroad
  3. LANG:C++
  4. TASK:msquare
  5. */
  6. #include
  7. #include
  8. #include
  9. #include
  10. using  namespace std ;
  11. ifstream fin ( "msquare.in" ) ;
  12. ofstream fout ( "msquare.out" ) ;
  13. typedef vector < int > VInt ;
  14. typedef  void Fun ( const VInt &, VInt & ) ;
  15. typedef Fun * FunPtr ;
  16.  
  17. const  int MAX_NUM   =  40321 ;
  18. const  int MSQUARE_SIZE  =  8 ;
  19. const  int FRAC [MSQUARE_SIZE ] =  { 1126241207205040 } ;
  20. const string sFlag  =  "ABC" ;
  21. bool HashTable [MAX_NUM ]  =  { 0 } ;
  22.  
  23. struct msquare
  24. {
  25.     msquare ( )  : vState (MSQUARE_SIZE ), sPath ( )  { }
  26.     VInt vState ;
  27.     string sPath ;
  28. } ;
  29.  
  30. deque <msquare > Q ;
  31.  
  32. void SwapRow ( const VInt & vSrc, VInt & vRes )
  33. {
  34.     vRes. resize ( 8 ) ;
  35.      int i, j  =  0 ;
  36.      for (=  4 ; i  <  8 ;  ++i,  ++j )
  37.         vRes [j ]  = vSrc [i ] ;
  38.      for (=  0 ; i  <  4 ;  ++i,  ++j )
  39.         vRes [j ]  = vSrc [i ] ;
  40. }
  41.  
  42. void SwapColumn ( const VInt & vSrc, VInt & vRes )
  43. {
  44.     vRes. resize ( 8 ) ;
  45.     vRes [ 0 ]  = vSrc [ 3 ] ;
  46.      for ( int i  =  1 ; i  <  4 ;  ++i )
  47.         vRes [i ]  = vSrc [i - 1 ] ;
  48.  
  49.     vRes [ 4 ]  = vSrc [ 7 ] ;
  50.      for ( int i  =  5 ; i  <  8 ;  ++i )
  51.         vRes [i ]  = vSrc [i - 1 ] ;
  52. }
  53.  
  54. void RotateMiddle ( const VInt & vSrc, VInt & vRes )
  55. {
  56.     vRes  = vSrc ;
  57.     vRes [ 1 ]  = vSrc [ 5 ] ;
  58.     vRes [ 2 ]  = vSrc [ 1 ] ;
  59.     vRes [ 5 ]  = vSrc [ 6 ] ;
  60.     vRes [ 6 ]  = vSrc [ 2 ] ;
  61. }
  62.  
  63. inline  int Contor (VInt & v )
  64. {
  65.      int ans  =  0 ;
  66.      for  ( int i  =  0 ; i  <  8 ; i ++ )
  67.      {
  68.          int tmp  =  0 ;
  69.          for  ( int j  = i + 1 ; j  <  8 ; j ++ )  if  (v [i ]  > v [j ] )  ++tmp ;
  70.         ans  + = tmp  * FRAC [ 7 -i ] ;
  71.      }
  72.      return ans + 1 ;
  73. }
  74.  
  75. int main ( )
  76. {
  77.     VInt vDest (MSQUARE_SIZE ), vStart (MSQUARE_SIZE ) ;
  78.      for ( int i  =  0 ; i  <  4 ;  ++i )
  79.         fin  >> vDest [i ] ;
  80.      for ( int i  =  7 ; i  >=  4 ;  --i )
  81.         fin  >> vDest [i ] ;
  82.  
  83.      for ( int i  =  0 ; i  <  4 ;  ++i )
  84.         vStart [i ]  = i  +  1 ;
  85.      for ( int i  =  7, j  =  4 ; i  >=  4 ;  --i,  ++j )
  86.         vStart [j ]  = i  +  1 ;
  87.  
  88.      if (vStart  == vDest )
  89.      {
  90.         fout  <<  0  << endl  << endl ;
  91.          return  0 ;
  92.      }
  93.  
  94.     FunPtr funArr [ 3 ] ;
  95.     funArr [ 0 ]  = SwapRow, funArr [ 1 ]  = SwapColumn, funArr [ 2 ]  = RotateMiddle ;
  96.  
  97.     msquare m ;
  98.     m. vState  = vStart ;
  99.     Q. push_back (m ) ;
  100.  
  101.     VInt vTmp ;
  102.      int HashValue  = Contor (vStart ) ;
  103.     HashTable [HashValue ]  =  true ;
  104.  
  105.      while ( !Q. empty ( ) )
  106.      {
  107.          for ( int i  =  0 ; i  <  3 ;  ++i )
  108.          {
  109.             m  = Q. front ( ) ;
  110.             vTmp. clear ( ) ;
  111.             funArr [i ] (m. vState, vTmp ) ;
  112.  
  113.              if (vTmp  == vDest )
  114.              {
  115.                 m. sPath  + = sFlag [i ] ;
  116.                  size_t size  = m. sPath. size ( ), start  =  0, len ;
  117.                 fout  << size  << endl ;
  118.                  while ( true )
  119.                  {
  120.                      if (size  >  60 )
  121.                      {
  122.                         len  =  60 ;
  123.                         start  + = len ;
  124.                         size  - = len ;
  125.                         fout  << string (m. sPath, start, len )  << endl ;
  126.                      }
  127.                      else
  128.                      {
  129.                         len  = size ;
  130.                         fout  << string (m. sPath, start, len )  << endl ;
  131.                          return  0 ;
  132.                      }
  133.                  }
  134.              }
  135.  
  136.             HashValue  = Contor (vTmp ) ;
  137.              if ( !HashTable [HashValue ] )
  138.              {
  139.                 m. vState  = vTmp ;
  140.                 m. sPath  + = sFlag [i ] ;
  141.                 Q. push_back (m ) ;
  142.                 HashTable [HashValue ]  =  true ;
  143.              }
  144.          }
  145.         Q. pop_front ( ) ;
  146.      }
  147.  
  148.      return  0 ;
  149. }


你可能感兴趣的:(USACO)