dp题,想了好久都没有想到什么好的方法。自己也写了好久都是一直wa。后来看了别人的想法,才恍然大悟。原来子的状态没有定义好。状态的定义还是的从基本的dp的最优子结构和无后效性考虑。这个题目值状态比较新颖。将每一行看作一个二进制数。然后定义dp[i][j]为第i行的各个位置状态为j时所能得到的数量,其转移方程为dp[i][j] = dp[i-1][k],概括的说就时,第i行状态为k时的结果为第i-1行中与状态j步冲突的状态的所有的和。具体处理中还要注意一些细节上的优化。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int a[15], ok[(1<<12)+1];
int d[13][(1<<12) + 1];
const int MOD = 100000000;
int main(){
int n,m;
while (scanf("%d%d",&n,&m) != EOF){
memset(d, 0, sizeof(d));
int tmp;
for (int i = 0; i<n; i++){
a[i] = 0;
for (int j = 0; j<m; j++){
scanf("%d",&tmp);
if (tmp){
a[i] = a[i] | (1<<j);
}
}
}
int cnt = 0;
for (int i = 0; i<(1<<m); i++){
int j;
for (j = 0; j<m-1; j++){
if ((i&(1<<j)) && (i&(1<<(j+1)))){
break;
}
}
if (j >= m-1){
ok[cnt++] = i;
}
}
for (int i = 0; i<cnt; i++){
if ((ok[i]&a[0]) == ok[i]) d[0][ok[i]] = 1;
}
for (int i = 1; i<n; i++){
for (int j = 0; j<cnt; j++){
if ((ok[j]&a[i]) != ok[j])continue;
for (int k = 0; k<cnt; k++){
if (ok[k]&ok[j]) continue;
d[i][ok[j]] = (d[i][ok[j]] + d[i-1][ok[k]]) % MOD;
}
}
}
int ans = 0;
for (int i = 0; i<cnt; i++) ans = (ans + d[n-1][ok[i]]) % MOD;
printf("%d\n",ans);
}
return 0;
}
本文深入探讨了一道复杂的DP算法题目,通过定义每行状态为一个二进制数的方法解决了问题。文章分享了从理解题目的最优子结构到实现的具体过程,并提供了一段C++代码示例,展示了如何通过状态转移方程进行高效计算。
816

被折叠的 条评论
为什么被折叠?



