#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
#define mod 100000000
int n , m;
int False[20000],True[20000],dp[14][20000];
bool search_(int a)
{
int b = (a >> 1);
if((a & b) == 0)
return true;
return false;
}
void solve()
{
int now = 1 << m;
int cnt = 1;
for(int i = 0 ; i < now ; i ++)
if(search_(i))//筛选出符合题意要求不相邻的情况.
True[cnt ++] = i;
for(int i = 1 ; i < cnt ; i ++)//初始化dp的第一行.
{
if((True[i] & False[1]) == 0)
dp[1][i] = 1;
}
//cout<<"Flase"<<False[2]<<endl;
for(int i = 2 ; i <= n ; i ++)//从第i行开始枚举,以第i行作为结尾
{
for(int j = 1 ; j < cnt ; j ++)//枚举第i行的所有情况
{
if((False[i]&True[j]) == 0)//选出符合条件的一种
{
for(int k = 1 ; k < cnt ; k ++)//枚举上一行的所有情况
{
if((True[k]&True[j]) == 0)//选出符合条件的一种(与上一行没有相邻的情况)
dp[i][j] = dp[i][j] + dp[i-1][k];//dp叠加
}
}
}
}
int ans = 0;
for(int i = 1 ; i < cnt ; i ++)
{
ans += dp[n][i];
ans = ans % mod;//题目要求取模
}
cout<<ans<<endl;
}
int main(void)
{
while(scanf("%d %d",&n , &m)!=EOF)
{
memset(dp,0,sizeof(dp));
memset(True,0,sizeof(True));
memset(False,0,sizeof(False));
int num;
for(int i = 1 ; i <= n ; i ++)
{
for(int j = 1 ; j <= m ; j ++)
{
cin>>num;
if(num == 0)
False[i] += (1<<(m-j));//每一行对应的一种不可能取到的情况:
//如果第一行为 1 1 0 , 则Flase[1]的二进制为 0 0 1 , 所以
//形如1 0 1 , 0 0 1 这些情况是不可取得
}
}
solve();
}
}
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
#define mod 100000000
int n , m;
int False[20000],True[20000],dp[14][20000];
bool search_(int a)
{
int b = (a >> 1);
if((a & b) == 0)
return true;
return false;
}
void solve()
{
int now = 1 << m;
int cnt = 1;
for(int i = 0 ; i < now ; i ++)
if(search_(i))//筛选出符合题意要求不相邻的情况.
True[cnt ++] = i;
for(int i = 1 ; i < cnt ; i ++)//初始化dp的第一行.
{
if((True[i] & False[1]) == 0)
dp[1][i] = 1;
}
//cout<<"Flase"<<False[2]<<endl;
for(int i = 2 ; i <= n ; i ++)//从第i行开始枚举,以第i行作为结尾
{
for(int j = 1 ; j < cnt ; j ++)//枚举第i行的所有情况
{
if((False[i]&True[j]) == 0)//选出符合条件的一种
{
for(int k = 1 ; k < cnt ; k ++)//枚举上一行的所有情况
{
if((True[k]&True[j]) == 0)//选出符合条件的一种(与上一行没有相邻的情况)
dp[i][j] = dp[i][j] + dp[i-1][k];//dp叠加
}
}
}
}
int ans = 0;
for(int i = 1 ; i < cnt ; i ++)
{
ans += dp[n][i];
ans = ans % mod;//题目要求取模
}
cout<<ans<<endl;
}
int main(void)
{
while(scanf("%d %d",&n , &m)!=EOF)
{
memset(dp,0,sizeof(dp));
memset(True,0,sizeof(True));
memset(False,0,sizeof(False));
int num;
for(int i = 1 ; i <= n ; i ++)
{
for(int j = 1 ; j <= m ; j ++)
{
cin>>num;
if(num == 0)
False[i] += (1<<(m-j));//每一行对应的一种不可能取到的情况:
//如果第一行为 1 1 0 , 则Flase[1]的二进制为 0 0 1 , 所以
//形如1 0 1 , 0 0 1 这些情况是不可取得
}
}
solve();
}
}
本文介绍了一种使用状态压缩动态规划解决特定组合问题的方法。通过定义状态、转移等关键步骤,详细解析了如何筛选并计数符合特定条件的排列组合。适用于解决约束条件明确的子集选择问题。
5927

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



