统计字典序元音字符串的数目
思路
可以缩短问题的规模,将其转换为相同类型的子问题。可以使用动态规划。
- 状态表示: dp[i][k] 为第 i 个数以第k个字母的字符结尾的元音字符串的数目。
- 状态转移方程: dp[i][k] = max j ∈ [ 0 , k ] ( d p [ i − 1 ] [ j ] ) + 1 \max_{j \in [0,k] }(dp[i-1][j]) + 1 maxj∈[0,k](dp[i−1][j])+1
- 边界条件 : dp[i][0~k] = 1, ( i ∈ n ) (i \in n) (i∈n)
代码实现
class Solution {
public int countVowelStrings(int n) {
int[] dp = new int[5];
for(int i = 0; i < 5; i++) dp[i] = 1;
int a, e, i, o, u;
for(int k = 1; k < n; k++){
a = dp[0];
e = dp[1];
i = dp[2];
o = dp[3];
u = dp[4];
dp[0] = a;
dp[1] = a + e;
dp[2] = a + e + i;
dp[3] = a + e + i + o;
dp[4] = a + e + i + o + u;
}
return Arrays.stream(dp).sum();
}
}
糖果
思路
状压dp,数据范围很小,可直接用二进制的形式表示当前这个数存在或者不存在。
*状态转移方程:dp[j | a[i]] = max(dp[j | a[i]], dp[j] + 1)
代码实现
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), m = sc.nextInt(), k = sc.nextInt();
int[] arr = new int[n + 1];
boolean[] vis = new boolean[m];
int tmp;
for(int i = 1; i <= n; i++){
for(int j = 0; j < k; j++){
tmp = sc.nextInt() - 1;
vis[tmp] = true;
arr[i] |= 1 << tmp;
}
}
for(int i = 0; i < m; i++){
if(!vis[i]){
System.out.println("-1");
return;
}
}
int[] f = new int[1 << m];
Arrays.fill(f, (int)1e9+7);
f[0] = 0;
for(int i = 1; i <= n; i++){
for(int j = (1<<m) -1; j >= 0; j--){
f[j | arr[i]] = Math.min(f[j | arr[i]], f[j] + 1);
}
}
System.out.println(f[(1<<m)-1]);
}
}