2023-07-09:给定N、M两个参数, 一共有N个格子,每个格子可以涂上一种颜色,颜色在M种里选, 当涂满N个格子,并且M种颜色都使用了,叫一种有效方法。 求一共有多少种有效方法。 1 <= N,
2023-07-09:给定N、M两个参数,
一共有N个格子,每个格子可以涂上一种颜色,颜色在M种里选,
当涂满N个格子,并且M种颜色都使用了,叫一种有效方法。
求一共有多少种有效方法。
1 <= N, M <= 5000。
返回结果比较大,请把结果 % 1000000007 之后返回。
答案2023-07-09:
这两种算法用于计算涂色的有效方法总数。
算法 ways1:
1.初始化路径数组 path,颜色是否使用的数组 set。
2.调用 process 函数,传入初始参数:路径数组 path,颜色是否使用的数组 set,当前处理的位置 i,格子数量 n,颜色种类 m。
3.如果当前位置 i 等于格子数量 n,即路径数组 path 已填满:
将颜色是否使用的数组
set中所有元素重置为false。统计路径数组
path中不重复的颜色数量,并记录在colors中。如果
colors等于颜色种类m,说明此路径是有效方法,返回 1;否则返回 0。
4.否则,遍历颜色种类 m 的所有可能颜色:
在路径数组
path当前位置i处填入该颜色。调用
process函数递归处理下一个位置i+1。将返回的结果累加到
ans上。
5.返回最终的结果 ans。
算法 ways2:
1.初始化动态规划数组 dp,大小为 MAXN × MAXN。
2.对于 dp 数组的第一行,设置每个位置的值为颜色种类 m。
3.使用两层循环,从第二行开始,依次计算每个位置 dp[i][j] 的值:
dp[i][j]等于前一行dp[i-1][j]乘以颜色种类j取模mod。添加额外的项,
dp[i][j]等于前一行dp[i-1][j-1]乘以剩余颜色种类m-j+1,然后加上之前的结果,再取模mod。
4.返回 dp[n][m] 的结果作为最终的答案。
功能测试:逐个测试从 1 到 9 的格子数量和颜色种类的组合,比较两种算法的结果是否一致,如果不一致则输出错误信息并中断。
性能测试:以 N=5000、M=4877 为例,计算两种算法的运行时间并打印结果。
算法 ways1 的时间复杂度为O(m^n),空间复杂度为O(n)。
算法 ways2 的时间复杂度为O(nm),空间复杂度为O(nm)。
go完整代码如下:
package main
import (
"fmt"
"time"
)
const MAXN = 5001
const mod = 1000000007
var dp [MAXN][MAXN]int
func ways1(n int, m int) int {
path := make([]int, n)
set := make([]bool, m+1)
return process(path, set, 0, n, m)
}
func process(path []int, set []bool, i int, n int, m int) int {
if i == n {
for j := 0; j <= m; j++ {
set[j] = false
}
colors := 0
for _, c := range path {
if !set[c] {
set[c] = true
colors++
}
}
if colors == m {
return 1
} else {
return 0
}
} else {
ans := 0
for j := 1; j <= m; j++ {
path[i] = j
ans += process(path, set, i+1, n, m)
}
return ans
}
}
func ways2(n int, m int) int {
for i := 1; i <= n; i++ {
dp[i][1] = m
}
for i := 2; i <= n; i++ {
for j := 2; j <= m; j++ {
dp[i][j] = int((int64(dp[i-1][j]) * int64(j)) % mod)
dp[i][j] = int((int64(dp[i-1][j-1])*(int64(m-j+1)) + int64(dp[i][j])) % mod)
}
}
return dp[n][m]
}
func main() {
N := 9
M := 9
fmt.Println("功能测试开始")
for n := 1; n <= N; n++ {
for m := 1; m <= M; m++ {
ans1 := ways1(n, m)
ans2 := ways2(n, m)
if ans1 != ans2 {
fmt.Println("出错了!")
fmt.Println("n : ", n)
fmt.Println("m : ", m)
fmt.Println("ans1 : ", ans1)
fmt.Println("ans2 : ", ans2)
break
}
}
}
fmt.Println("功能测试结束")
fmt.Println("性能测试开始")
n := 5000
m := 4877
fmt.Println("n : ", n)
fmt.Println("m : ", m)
start := currentTimeMillis()
ans := ways2(n, m)
end := currentTimeMillis()
fmt.Println("取余之后的结果 : ", ans)
fmt.Println("运行时间 : ", (end - start), " 毫秒")
fmt.Println("性能测试结束")
}
func currentTimeMillis() int64 {
return time.Now().UnixNano() / int64(time.Millisecond)
}

rust完整代码如下:
fn ways1(n: i32, m: i32) -> i32 {
let mut path = vec![0; n as usize];
let mut set = vec![false; (m + 1) as usize];
process(&mut path, &mut set, 0, n, m)
}
fn process(path: &mut [i32], set: &mut [bool], i: i32, n: i32, m: i32) -> i32 {
if i == n {
set.iter_mut().for_each(|x| *x = false);
let mut colors = 0;
for &c in path.iter() {
if !set[c as usize] {
set[c as usize] = true;
colors += 1;
}
}
return if colors == m { 1 } else { 0 };
} else {
let mut ans = 0;
for j in 1..=m {
path[i as usize] = j;
ans += process(path, set, i + 1, n, m);
}
ans
}
}
const MAXN: usize = 5001;
const MOD: i64 = 1000000007;
static mut DP: [[i32; MAXN]; MAXN] = [[0; MAXN]; MAXN];
fn ways2(n: i32, m: i32) -> i32 {
unsafe {
for i in 1..=n {
DP[i as usize][1] = m;
}
for i in 2..=n {
for j in 2..=m {
DP[i as usize][j as usize] =
((DP[(i - 1) as usize][j as usize] as i64 * j as i64) % MOD) as i32;
DP[i as usize][j as usize] = (((DP[(i - 1) as usize][(j - 1) as usize] as i64
* (m - j + 1) as i64)
+ DP[i as usize][j as usize] as i64)
% MOD) as i32;
}
}
DP[n as usize][m as usize]
}
}
fn main() {
let n: i32 = 9;
let m: i32 = 9;
println!("功能测试开始");
for n_val in 1..=n {
for m_val in 1..=m {
let ans1 = ways1(n_val, m_val);
let ans2 = ways2(n_val, m_val);
if ans1 != ans2 {
println!("出错了!");
println!("n : {}", n_val);
println!("m : {}", m_val);
println!("ans1 : {}", ans1);
println!("ans2 : {}", ans2);
break;
}
}
}
println!("功能测试结束");
println!("性能测试开始");
let n_val: i32 = 5000;
let m_val: i32 = 4877;
println!("n : {}", n_val);
println!("m : {}", m_val);
let start = std::time::Instant::now();
let ans = ways2(n_val, m_val);
let duration = start.elapsed();
println!("取余之后的结果 : {}", ans);
println!("运行时间 : {} 毫秒", duration.as_millis());
println!("性能测试结束");
}

c++完整代码如下:
#include <iostream>
#include <vector>
using namespace std;
const int MAXN = 5001;
const int mod = 1000000007;
vector<vector<int>> dp(MAXN, vector<int>(MAXN, 0));
int process(vector<int>& path, vector<bool>& set, int i, int n, int m);
int ways1(int n, int m) {
vector<int> path(n, 0);
vector<bool> set(m + 1, false);
return process(path, set, 0, n, m);
}
int process(vector<int>& path, vector<bool>& set, int i, int n, int m) {
if (i == n) {
fill(set.begin(), set.end(), false);
int colors = 0;
for (int c : path) {
if (!set[c]) {
set[c] = true;
colors++;
}
}
return colors == m ? 1 : 0;
}
else {
int ans = 0;
for (int j = 1; j <= m; j++) {
path[i] = j;
ans += process(path, set, i + 1, n, m);
}
return ans;
}
}
int ways2(int n, int m) {
for (int i = 1; i <= n; i++) {
dp[i][1] = m;
}
for (int i = 2; i <= n; i++) {
for (int j = 2; j <= m; j++) {
dp[i][j] = ((long)dp[i - 1][j] * j) % mod;
dp[i][j] = (((long)dp[i - 1][j - 1] * (m - j + 1)) + dp[i][j]) % mod;
}
}
return dp[n][m];
}
int main() {
int N = 9;
int M = 9;
cout << "功能测试开始" << endl;
for (int n = 1; n <= N; n++) {
for (int m = 1; m <= M; m++) {
int ans1 = ways1(n, m);
int ans2 = ways2(n, m);
if (ans1 != ans2) {
cout << "出错了!" << endl;
cout << "n : " << n << endl;
cout << "m : " << m << endl;
cout << "ans1 : " << ans1 << endl;
cout << "ans2 : " << ans2 << endl;
break;
}
}
}
cout << "功能测试结束" << endl;
cout << "性能测试开始" << endl;
int n = 5000;
int m = 4877;
cout << "n : " << n << endl;
cout << "m : " << m << endl;
long long start = clock();
int ans = ways2(n, m);
long long end = clock();
cout << "取余之后的结果 : " << ans << endl;
cout << "运行时间 : " << (end - start) << " 毫秒" << endl;
cout << "性能测试结束" << endl;
return 0;
}

2023-07-09:给定N、M两个参数, 一共有N个格子,每个格子可以涂上一种颜色,颜色在M种里选, 当涂满N个格子,并且M种颜色都使用了,叫一种有效方法。 求一共有多少种有效方法。 1 <= N,的更多相关文章
- 已知n个数的入栈序列,求一共有多少种出栈序列 (卡特兰数)
已知\(n\)个数的入栈序列,求一共有多少种出栈序列 这个经典问题有两种解法. 解法一: 设\(f(x)\)为\(x\)个数入栈后,再全部出栈的序列数量 假设我们有\(4\)个数\(a,b,c,d\) ...
- 有n个台阶,如果一次只能上1个或2个台阶,求一共有多少种上法
// n级台阶,求多少种跳法.cpp : Defines the entry point for the console application. // /* 思路: 如果只有一级台阶,n=1,很明显 ...
- hdu2049 不容易系列之(4)——考新郎 错排+组合 一共有N对新婚夫妇,N个新娘随机坐成一排,每个新郎只能选一个, 其中有M个新郎找错了新娘,求发生这种情况一共有多少种可能.
不容易系列之(4)——考新郎 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)To ...
- 算法基础_递归_给定m个A,n个B,一共有多少种排列
问题描述: 给定m个A,n个B,一共有多少种排列 解题源代码: /** * 给定m个A,n个B,问一共有多少种排列 * @author Administrator * */ public class ...
- n个台阶,每次都可以走一步,走两步,走三步,走到顶部一共有多少种可能
分析 第一个台阶 1第二个台阶 11 2 //走两次1步或者走1次两步第三个台阶 111 12 21 3 第四个台阶 1111 112 121 211 22 13 31 思想:4阶台阶, ...
- Android 一共有多少种动画?准确告诉你!
Android 动画 Android 动画在开发中是不可或缺的功能,或者说是界面灵动的添加剂.那你是否总结过 Android 中总共为开发者提供了多少种方式的动画呢?今天就为大家总结归纳一下. 报 ...
- python假设一段楼梯共 n(n>1)个台阶,小朋友一步最多能上 3 个台阶,那么小朋友上这段楼 梯一共有多少种方法
我们先把前四节种数算出来(自己想是哪几类,如果你不会算,那就放弃写代码吧,干一些在街上卖肉夹馍的小生意,也挣得不少) 标号 1 2 3 4 种类 1 2 4 7 ...
- 爬楼梯,N级楼梯有多少种走法?
https://blog.csdn.net/tcpipstack/article/details/45173685 一个人爬楼梯,一步可以迈一级,二级,三级台阶,如果楼梯有N级,要求编写程序,求总共有 ...
- F - Goldbach`s Conjecture 对一个大于2的偶数n,找有多少种方法使两个素数的和为n;保证素数a<=b; a+b==n; a,b都为素数。
/** 题目:F - Goldbach`s Conjecture 链接:https://vjudge.net/contest/154246#problem/F 题意:对一个大于2的偶数n,找有多少种方 ...
- 2021.07.09 K-D树
2021.07.09 K-D树 前置知识 1.二叉搜索树 2.总是很长的替罪羊树 K-D树 建树 K-D树具有二叉搜索树的形态,对于每一个分类标准,小于标准的节点在父节点左边,大于标准的节点在父节点右 ...
随机推荐
- day118:MoFang:根据激活/未激活的状态分别显示树桩&种植植物&解锁树桩&化肥/修剪/浇水/宠物粮小图标数字的显示
登录 1.根据激活状态和未激活状态分别显示树桩 2.用户使用植物道具进行果树种植 3.解锁树桩 4.化肥/修剪/浇水/宠物粮小图标显示 种植栏的功能实现 1. 客户端需要的植物相关参数: 总树桩数量, ...
- 【Spring注解驱动】(三)servlet3.0
前言 今天是7.21日,终于是看完了..暑假在家学习是真的差点意思 1 Servlet 3.0简介 Servlet 2.0是在web.xml中配置servlet filter.listener.Dis ...
- 每天掌握10道面试题,轻轻松松去面试(Yes, that's right, I'm kidding)!!!
一.4.12 1.说一说cookie sessionStorage localStorage 是什么,有什么区别? Cookie.sessionStorage 和 localStorage 都是在浏览 ...
- JS执行机制--同步与异步
单线程JavaScript语言具有单线程的特点,同一个时间只能做一件事情.这是因为JavaScript脚本语言是为了处理页面中用户的交互,以及操作DOM而诞生的.如果对某个DOM元素进行添加和删除,不 ...
- 关于spring嵌套事务,我发现网上好多热门文章持续性地以讹传讹
事情起因是,摸鱼的时候在某平台刷到一篇spring事务相关的博文,文章最后贴了一张图.里面关于嵌套事务的表述明显是错误的. 更奇怪的是,这张图有点印象.在必应搜索关键词PROPAGATION_NEST ...
- 第3章. markdown语法
常用语法 1. 文字格式 1.1 给文字添加引用 在文字的两侧,使用 ` 符号包裹起来 怒发冲冠,凭栏处,潇潇雨歇. 1.2 设置文字样式为斜体 在文字的两侧,使用 * 符号包裹起来 抬望眼,仰天长啸 ...
- 突破传统监测模式:业务状态监控HM的新思路
作者:京东保险 管顺利 一.传统监控系统的盲区,如何打造业务状态监控. 在系统架构设计中非常重要的一环是要做数据监控和数据最终一致性,关于一致性的补偿,已经由算法部的大佬总结过就不在赘述.这里主要讲如 ...
- 案例分享-full gc导致k8s pod重启
在之前的记一次k8s pod频繁重启的优化之旅中分享过对于pod频繁重启的一些案例,最近又遇到一例,继续分享出来希望能给大家带来些许收获. 问题现象 报警群里突然显示某pod频繁重启,我随即上去查看日 ...
- Linux 给用户赋予操作权限
赋予local目录读写权限给keesail,别的用户对这个目录没有任何权限. chown -R keesail:keesail ./local chmod 777 文件夹名称,可以把文件夹设置成所有用 ...
- 2021-01-05:mysql的自增id的实现逻辑是什么样子的?
福哥答案2021-01-05:答案来自这个链接:[ 每日一面 - mysql 的自增 id 的实现逻辑是什么样子的?](https://zhanghaoxin.blog.csdn.net/articl ...