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 <fstream>
  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 <fstream>
  7. #include <vector>
  8. #include <deque>
  9. #include <string>
  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. }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章