列表

详情


1931. 用三种不同颜色为网格涂色

给你两个整数 mn 。构造一个 m x n 的网格,其中每个单元格最开始是白色。请你用 红、绿、蓝 三种颜色为每个单元格涂色。所有单元格都需要被涂色。

涂色方案需要满足:不存在相邻两个单元格颜色相同的情况 。返回网格涂色的方法数。因为答案可能非常大, 返回 109 + 7 取余 的结果。

 

示例 1:

输入:m = 1, n = 1
输出:3
解释:如上图所示,存在三种可能的涂色方案。

示例 2:

输入:m = 1, n = 2
输出:6
解释:如上图所示,存在六种可能的涂色方案。

示例 3:

输入:m = 5, n = 5
输出:580986

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int colorTheGrid(int m, int n) { } };

java 解法, 执行用时: 42 ms, 内存消耗: 42.2 MB, 提交时间: 2023-09-28 23:10:48

class Solution {
    public int colorTheGrid(int m, int n) {
        final int MOD = 1_000_000_007;
        // key 为有效的 mask 值,value 为 mask 值对应的 3 进制数
        Map<Integer, int[]> valid = new HashMap<>();
        int maskEnd = (int)Math.pow(3, m);

        // 初始化 valid 
        for(int mask = 0; mask < maskEnd; ++mask){
            int[] color = new int[m];
            int mm = mask;
            // 分析三进制值,如果相邻两个值相同,则不符合要求,舍弃
            boolean check = true;
            for(int i = 0; i < m; ++i){
                color[i] = mm % 3;
                if(i > 0 && color[i-1] == color[i]) check = false;
                mm /= 3;
            }
            if(check) valid.put(mask, color);  
        }

        // 预处理,分析所有可能相邻的二元组,将该信息放置在 map 中
        // key 值为 mask 值,value 为可与该 mask 相邻的 mask 值列表
        Map<Integer, List<Integer>> adjacent = new HashMap<>();
        for(Integer mask1 : valid.keySet()){
            List<Integer> list = new ArrayList<>();
            for(Integer mask2 : valid.keySet()){
                boolean check = true;
                for(int i = 0; i < m; ++i){
                    if(valid.get(mask1)[i] == valid.get(mask2)[i]){
                        check = false;
                        break;
                    }
                }
                if(check) list.add(mask2);
            }
            adjacent.put(mask1, list);
        }

        // 由于 dp[i][mask] 仅与 dp[i-1][mask'] 有关,因此,可以使用一维数组实现 dp
        int[] dp = new int[maskEnd];

        // 边界条件:dp[i][mask], i == 0 时
        for(Integer mask : valid.keySet()){
            dp[mask] = 1;
        }

        // 动态规划
        for(int i = 1; i < n; ++i){
            int[] tmpDp = new int[maskEnd];
            for(Integer mask : valid.keySet()){
                for(Integer index : adjacent.get(mask)){
                    tmpDp[mask] += dp[index];
                    tmpDp[mask] %= MOD;
                }
            }
            dp = tmpDp;
        }
        
        int ans = 0;
        for(Integer mask : valid.keySet()){
            ans += dp[mask];
            ans %= MOD;
        }
        return ans;
    }
}

python3 解法, 执行用时: 380 ms, 内存消耗: 16.2 MB, 提交时间: 2023-09-28 23:10:24

'''
f[i][mask] 表示我们已经对 0,1,⋯ ,i 行进行了涂色,并且第 i 行的涂色方案对应的三进制表示为 mask 的前提下的总方案数。
'''
class Solution:
    def colorTheGrid(self, m: int, n: int) -> int:
        mod = 10**9 + 7
        # 哈希映射 valid 存储所有满足要求的对一行进行涂色的方案
        # 键表示 mask,值表示 mask 的三进制串(以列表的形式存储)
        valid = dict()
        
        # 在 [0, 3^m) 范围内枚举满足要求的 mask
        for mask in range(3**m):
            color = list()
            mm = mask
            for i in range(m):
                color.append(mm % 3)
                mm //= 3
            if any(color[i] == color[i + 1] for i in range(m - 1)):
                continue
            valid[mask] = color
        
        # 预处理所有的 (mask1, mask2) 二元组,满足 mask1 和 mask2 作为相邻行时,同一列上两个格子的颜色不同
        adjacent = defaultdict(list)
        for mask1, color1 in valid.items():
            for mask2, color2 in valid.items():
                if not any(x == y for x, y in zip(color1, color2)):
                    adjacent[mask1].append(mask2)
        
        f = [int(mask in valid) for mask in range(3**m)]
        for i in range(1, n):
            g = [0] * (3**m)
            for mask2 in valid.keys():
                for mask1 in adjacent[mask2]:
                    g[mask2] += f[mask1]
                    if g[mask2] >= mod:
                        g[mask2] -= mod
            f = g
            
        return sum(f) % mod

cpp 解法, 执行用时: 72 ms, 内存消耗: 17.5 MB, 提交时间: 2023-09-28 23:08:32

class Solution {
private:
    static constexpr int mod = 1000000007;

public:
    int colorTheGrid(int m, int n) {
        // 哈希映射 valid 存储所有满足要求的对一行进行涂色的方案
        // 键表示 mask,值表示 mask 的三进制串(以列表的形式存储)
        unordered_map<int, vector<int>> valid;

        // 在 [0, 3^m) 范围内枚举满足要求的 mask
        int mask_end = pow(3, m);
        for (int mask = 0; mask < mask_end; ++mask) {
            vector<int> color;
            int mm = mask;
            for (int i = 0; i < m; ++i) {
                color.push_back(mm % 3);
                mm /= 3;
            }
            bool check = true;
            for (int i = 0; i < m - 1; ++i) {
                if (color[i] == color[i + 1]) {
                    check = false;
                    break;
                }
            }
            if (check) {
                valid[mask] = move(color);
            }
        }

        // 预处理所有的 (mask1, mask2) 二元组,满足 mask1 和 mask2 作为相邻行时,同一列上两个格子的颜色不同
        unordered_map<int, vector<int>> adjacent;
        for (const auto& [mask1, color1]: valid) {
            for (const auto& [mask2, color2]: valid) {
                bool check = true;
                for (int i = 0; i < m; ++i) {
                    if (color1[i] == color2[i]) {
                        check = false;
                        break;
                    }
                }
                if (check) {
                    adjacent[mask1].push_back(mask2);
                }
            }
        }

        vector<int> f(mask_end);
        for (const auto& [mask, _]: valid) {
            f[mask] = 1;
        }
        for (int i = 1; i < n; ++i) {
            vector<int> g(mask_end);
            for (const auto& [mask2, _]: valid) {
                for (int mask1: adjacent[mask2]) {
                    g[mask2] += f[mask1];
                    if (g[mask2] >= mod) {
                        g[mask2] -= mod;
                    }
                }
            }
            f = move(g);
        }

        int ans = 0;
        for (int num: f) {
            ans += num;
            if (ans >= mod) {
                ans -= mod;
            }
        }
        return ans;
    }
};

golang 解法, 执行用时: 4 ms, 内存消耗: 5.4 MB, 提交时间: 2023-09-28 23:07:47

const mod int = 1e9 + 7

func colorTheGrid(m, n int) (ans int) {
	m *= 2
	// 预处理所有合法状态:用四进制表示颜色
	valid := []int{}
outer:
	for mask := 0; mask < 1<<m; mask++ {
		pre := 0
		for j := 0; j < m; j += 2 {
			color := mask >> j & 3
			if color == 0 || color == pre { // 未涂色或相邻颜色相同
				continue outer
			}
			pre = color
		}
		valid = append(valid, mask)
	}

	// 预处理所有合法状态能转移到哪些合法状态(记录合法状态的下标)
	to := make([][]int, len(valid))
	for i, v := range valid {
	o:
		for j, w := range valid {
			for k := 0; k < m; k += 2 {
				if v>>k&3 == w>>k&3 { // 相邻颜色相同
					continue o
				}
			}
			to[i] = append(to[i], j)
		}
	}

	// 滚动数组,用当前行更新下一行不同状态的方案数
	dp := make([]int, len(valid))
	for i := range dp {
		dp[i] = 1
	}
	for i := 1; i < n; i++ {
		tmp := dp
		dp = make([]int, len(valid))
		for j, dv := range tmp {
			for _, t := range to[j] {
				dp[t] = (dp[t] + dv) % mod
			}
		}
	}
	for _, dv := range dp {
		ans += dv
	}
	return ans % mod
}

上一题