Maximize Grid Happiness 最大化网格幸福感
问题描述:
给你四个整数 m、n、introvertsCount 和 extrovertsCount 。有一个 m x n 网格,和两种类型的人:内向的人和外向的人。总共有 introvertsCount 个内向的人和 extrovertsCount 个外向的人。
请你决定网格中应当居住多少人,并为每个人分配一个网格单元。 注意,不必 让所有人都生活在网格中。
每个人的 幸福感 计算如下:
内向的人 开始 时有 120 个幸福感,但每存在一个邻居(内向的或外向的)他都会 失去 30 个幸福感。
外向的人 开始 时有 40 个幸福感,每存在一个邻居(内向的或外向的)他都会 得到 20 个幸福感。
邻居是指居住在一个人所在单元的上、下、左、右四个直接相邻的单元中的其他人。
网格幸福感 是每个人幸福感的 总和 。 返回 最大可能的网格幸福感 。
n,m 范围[1,5] ,introvertsCount, extrovertsCount 范围[0,min(m * n, 6)]
分析
动态规划还是基于上一版本的DFS自底向上做的递推。
时间复杂度与空间复杂度和之前的DFS属于同一等级。状态转移方程参考以下:
f [ i ] [ i n ] [ e x ] [ s t a t e ] = max ( f [ i ] [ i n − c u r i n ] [ e x − c u r e x ] [ p r e s t a t e ] + s c o r e [ s t a t e ] [ p r e s t a t e ] ) c u r i n 当前 i 行 i n t r o 的人数、 c u r e x 当前 i 行 e x t r o 的人数 s c o r e [ i ] [ j ] 当前行状态 i 与上一行状态 j 的影响产生的得分 f[i][in][ex][state] = \max ( f[i][in-curin][ex-curex][prestate] + score[state][prestate])\\ curin 当前i行intro的人数、 curex 当前i行extro的人数\\ score[i][j] 当前行状态i与上一行状态j的影响产生的得分 f[i][in][ex][state]=max(f[i][in−curin][ex−curex][prestate]+score[state][prestate])curin当前i行intro的人数、curex当前i行extro的人数score[i][j]当前行状态i与上一行状态j的影响产生的得分
代码
class Solution {
static final int T = 243, N = 5, M = 6;
int n, m, tot;
int[][] maskBits;
int[] ivCount;
int[] evCount;
int[] innerScore;
int[][] interScore;
int[][][][] d;
// 邻居间的分数
static int[][] score = {
{0, 0, 0},
{0, -60, -10},
{0, -10, 40}
};
public int getMaxGridHappiness(int m, int n, int introvertsCount, int extrovertsCount) {
this.n = n;
this.m = m;
// 状态总数为 3^n
this.tot = (int) Math.pow(3, n);
this.maskBits = new int[T][N];
this.ivCount = new int[T];
this.evCount = new int[T];
this.innerScore = new int[T];
this.interScore = new int[T][T];
int[][][][] f = new int[N+1][M + 1][M + 1][T];
this.d = new int[N][T][M + 1][M + 1];
int excount =extrovertsCount;
int incount =introvertsCount;
int ans =0;
initData();
for (int i = 0; i <= m; i++) {
for (int in = 0; in <= incount; in++) {
for (int ex = 0; ex <= excount; ex++) {
Arrays.fill(f[i][in][ex], -1);
}
}
}
f[0][0][0][0] = 0;
for (int i = 1; i <= m; i++) {
for (int in = 0; in <= incount; in++) {
for (int ex = 0; ex <= excount; ex++) {
for (int state = 0; state < T; state++) {
int curin = ivCount[state];
if(in<curin) continue;
int curex = evCount[state];
if(ex<curex) continue;
int prein = in-curin;
int preex = ex-curex;
for (int prestate = 0; prestate < T; prestate++) {
if (f[i-1][prein][preex][prestate]==-1){
continue;
}
int v = innerScore[state];
v+=interScore[prestate][state];
f[i][in][ex][state]=Math.max(f[i][in][ex][state],f[i-1][prein][preex][prestate]+v);
}
if (i==m) ans = Math.max(ans, f[i][in][ex][state]);
}
}
}
}
return ans;
}
public void initData() {
// 计算行内分数
for (int mask = 0; mask < tot; mask++) {
int maskTmp = mask;
for (int i = 0; i < n; i++) {
int x = maskTmp % 3;
maskBits[mask][i] = x;
maskTmp /= 3;
if (x == 1) {
ivCount[mask]++;
innerScore[mask] += 120;
} else if (x == 2) {
evCount[mask]++;
innerScore[mask] += 40;
}
if (i > 0) {
innerScore[mask] += score[x][maskBits[mask][i - 1]];
}
}
}
// 计算行间分数
for (int i = 0; i < tot; i++) {
for (int j = 0; j < tot; j++) {
interScore[i][j] = 0;
for (int k = 0; k < n; k++) {
interScore[i][j] += score[maskBits[i][k]][maskBits[j][k]];
}
}
}
}
}
时间复杂度 O ( m ∗ i v ∗ e v ∗ 3 2 n ) O(m*{iv}*{ev}*{3^{2n}}) O(m∗iv∗ev∗32n)
空间复杂度 O ( m ∗ i v ∗ e v ∗ 3 n ) O(m*{iv}*{ev}*{3^{n}}) O(m∗iv∗ev∗3n)
动态规划版填坑文章来源:https://www.toymoban.com/news/detail-500243.html
Tag
Memoization
Bit Manipulation
Dynamic Programming
Bitmask
文章来源地址https://www.toymoban.com/news/detail-500243.html
到了这里,关于【算法】Maximize Grid Happiness 最大化网格幸福感 动态规划的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!