序列型动规
d[i]中的i表示前i的元素的某种性质。
有一排N栋房子,每栋房子要漆成K种颜色中的一种
任何两栋相邻的房子不能漆成同样的颜色
房子i染成第j种颜色的花费是cost[i][j]
问最少需要花多少钱油漆这些房子
输入;
N = 3, K = 3
Cost = [[14,2,11],[11,14,5],[14,3,10]]
输出:
10(房子0蓝色,房子1绿色,房子2蓝色, 2+5+3=10)
需要记录油漆前i栋房子并且房子i-1是颜色1, 颜色2,…,颜色K的最小花费·:d[i][1], d[i][2], …,d[i][k]
转移方程:
d[i][j] = min(k不等于j){d[i-1][k]}+cost[i-1][j];
时间复杂度O(NK^2)
每次需要求d[i-1][1],…,d[i-1][K]中除了一个元素之外其他元素的最小值
优化
如果最小值是第i个元素,次小值是第j个元素
1.只要除掉的元素不是第i个,剩下的最小值就是第i个元素
2.如果除掉的元素是第i个,剩下的最小值就是第j个元素
记录下最小值和次小值
复杂度降为O(NK)
#include <cstdio>
#include <algorithm>
using namespace std;
int d[10000][10000], cost[10000][10000], n, k;
int main() {
int min1, min2;
int id1, id2;
scanf("%d%d", &n, &k);
for(int i = 0; i < n; i++) {
for(int j = 0; j < k; j++) {
scanf("%d", &cost[i][j]);
}
}
for(int i = 0; i < k; i++) {
d[0][i] = 0;
}
for(int i = 1; i <= n; i++) {
min1 = 0x3f3f3f3f;
min2 = 0x3f3f3f3f;
for(int j = 0; j < k; j++) {
if(d[i - 1][j] < min1) {
min2 = min1;
id2 = id1;
min1 = d[i - 1][j];
id1 = j;
}
else {
if(d[i - 1][j] < min2) {
min2 = d[i - 1][j];
id2 = j;
}
}
}
for(int j = 0; j < k; j++) {
d[i][j] = cost[i - 1][j];
if(j != id1) {
d[i][j] += min1;
}
else{
d[i][j] += min2;
}
}
}
int res = 0x3f3f3f3f;
for(int i = 0; i < k; i++) {
res = min(res, d[n][i]);
}
printf("%d", res);
return 0;
}