1. 程式人生 > >lintcode 染色問題

lintcode 染色問題

lintcode 染色問題

描述

有一個圓形,分成n個扇形,用m種顏色給每個扇形染色,相鄰扇形顏色不能相同。求方案總數。

不考慮對稱性。
由於這個數可能很大,因此只需返回方案數模1e9 + 7。
1≤n≤1051  1≤n≤10​^5​​
1≤m≤1051 1≤m≤10​5​^5

樣例

給定n = 2,m = 3,返回6。

解釋:
一個圓劃分為 2 個扇形,用 3 種顏色上色方案有“黑紅,黑白,白紅,白黑,紅白,紅黑”6 種。

給定 n = 3,m = 2,返回 0。

解釋:
一個圓劃分為 3 個扇形,用 2 種顏色上色,無論怎麼上色,都沒法保證相鄰的顏色不同。

思路

使用動態規劃,考慮每多1塊扇形可能的情況:

  1. 多的這一塊扇形兩邊的顏色不一樣
    如此,多的這一塊有m-2種填法,剩下的n-1塊的填法是f(n-1)。一共是f(n-1) * (m-2)
  2. 多的這一塊兩邊的扇形顏色一樣
    多的這一塊有m-1種,剩下的圖形是f(n-2)

兩者相加就可以得到遞推式:
f(n) = (m-1)f(n-2) + (m-2)f(n-1)

class Solution {
public:
    /**
     * @param n: the number of sectors
     * @param m: the number of colors
     * @return: The total number of plans.
     */
    int getCount(int n, int m) {
        // Write your code here
        vector<unsigned long long> dp(n+2, 0);
        unsigned long long mod = 1e9+7;
        dp[0] = 0;
        dp[1] = m;
        dp[2] = (unsigned long long)m*(m-1) % mod;
        dp[3] = (unsigned long long)m*(m-1)*(m-2) % mod;
        for (int i = 4; i < n+1; i++)
            dp[i] = ((m-2)*dp[i-1] + (m-1)*dp[i-2]) % mod;
        return dp[n];
    }
};

這裡要注意的是,dp[2] = (unsigned long long)m*(m-1) % mod;
dp[3] = (unsigned long long)m*(m-1)*(m-2) % mod;這兩行,一開始的時候我沒有加上強制型別轉換 (unsigned long long)得出的結果一直是錯的,加上之後就正確了。我猜想是因為m的型別是int,運算完m*(m-1)*(m-2)之後很有可能溢位了。所以我對這個操作進行了測試。

  int int_m = 1999;
  
  unsigned long long ull_m = 1999;
  
  cout << "int: " << int_m * int_m * int_m << endl;

  cout << "int(unsigned long long): " << 
  	(unsigned long long)int_m * int_m * int_m << endl;
  
  cout << "unsigned long long: "<< ull_m * ull_m * ull_m << endl;

第一行輸出為 -601928593
第二行輸出為 7988005999
第三行輸出為 7988005999
結果顯而易見了。在運算的時候,遇到大數,一定要注意精度的問題。