【题目大意】一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻。问有多少种放牛方案(一头牛都不放也是一种方案)
额,好像是玉米。。
举个例子:
2 3
1 1 1
0 1 0
表示2*3的玉米地,现在一共有多少种种植方法呢? 答案:种0个玉米(算一个合法方案)+种1个玉米(4)+种2个玉米(3)+种3个玉米(1)=9
题解:
PS:位运算的优先级相当的低,一般情况下多打几个()来提高优先级终归是好习惯。
这个题目,考虑,将每个点是否种植玉米若种就在相应的二进制表示。
然后每一行的种植方案就和前一行有关。所以当当前状态合理,前一排的状态合理,且两行没有在相同位置为1。似乎作为动规来说这个题目难度不大,主要难度在用二进制表示每个状态和判断每一个状态是否合理。
1:判断这个状态是否能种
S【i】是表示的每一个不能种玉米的地方;
若state & s【i】 != 0则在不能种玉米的地方种植了玉米。
2:inline bool check_T(int y,int state){
bool c = false;int h = 1;
for(;h <= state;h <<= 1)
{
if(state & h && c == true) return false;
c = false;
if(state & h) c = true;
}
return true;
}
这个函数就是枚举的对于一种种植方案是否有同一行相邻位置种植了玉米,也就是对应的是否有在状态的二进制表示中有连续两个1;
3:(j & k) == 0 这个就是我的两行中相邻位置有没有都种植玉米,所以相对应的情况下就是两个状态i和状态j的二进制表示中有没有同一个位子都为1。
代码
#include <iostream>
#include <cstdio>
const int MOD = 100000000;
using namespace std;
int N,M,Max,ans,dp[20][10000],S[15];
bool Map;
inline bool check(int y,int state){ //判断状态是否可行
if(S[y] & state) return false;
return true;
}
inline bool check_T(int y,int state){
bool c = false;int h = 1;
for(;h <= state;h <<= 1)
{
if(state & h && c == true) return false;
c = false;
if(state & h) c = true;
}
return true;
}
int main()
{
scanf("%d %d",&M,&N);
for(int i = 0;i < M;i++)
for(int j = 1;j <= N;j++){
scanf("%d",&Map);
if(Map == 0) S[j] += 1 << i;
}
Max = (1 << M) - 1;
for(int i = 0;i <= Max;i++) //循环边界
if(check(1,i) && check_T(1,i)) dp[1][i] = 1;
for(int i = 2;i <= N;i++)
for(int j = 0;j <= Max;j++)
{
if(check(i,j) && check_T(i,j)){
for(int k = 0;k <= Max;k++)
if((j & k) == 0 && check(i-1,k) && check_T(i-1,k))
dp[i][j] += dp[i-1][k];
}
}
for(int i = 0;i <= Max;i++)
ans += dp[N][i],
ans %= MOD;
cout<<ans;
}