POJ3254 Corn Fields(状态DP)

【POJ3254】Corn Fields

【题目大意】一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不可以放牧,可以放牧用1表示,否则用0表示,在这块牧场放牛,要求

     (1)两个相邻的方格不能同时放牛,即牛与牛不能相邻。问有多少种放牛方案(一头牛都不放也是一种方案)

【解析】根据题意,把每一行的状态用二进制的数表示,0代表不在这块放牛,1表示在这一块放牛。

const int Max_N = 4100 ;
const int Mod = 100000000 ;
int N , M ;
int dp[13][Max_N] ;/*截止到(第i行,状态为j)的中情况数*/  
int cannot[13] ; //第i行已经不能放的初始情况  
/*判断状态i是否满足左右不相邻*/  
int ok(int x){
    if(x & (x<<1))
      return 0 ;
    if(x & (x>>1))
      return 0 ;
    return 1 ;
}

void get_all_states(vector<int> &states){
     states.clear() ;
     for(int i = 0 ; i < (1<<M) ; i++){
        if(ok(i))
           states.push_back(i) ;
     }
}

int DP(){
    int i , j , row ;
    vector<int> state ;
    get_all_states(state) ;
    memset(dp , 0 , sizeof(dp)) ;
    for(i = 0 ; i < state.size() ; i++){
        if(state[i] & cannot[1])
            continue ;
        dp[1][state[i]] = 1 ;
    }
    for(row = 2 ; row <= N ; row++){
        for(i = 0 ; i < state.size() ; i++){
            if(state[i] & cannot[row])
                continue ;
            for(j = 0 ; j < state.size() ; j++){
                if(state[j] & cannot[row-1])
                    continue ;
                if(state[i] & state[j]) //上下不相邻  
                    continue ;
                dp[row][state[i]] += dp[row-1][state[j]] ;
                dp[row][state[i]] %= Mod ;
            }
        }
    }
    int ans = 0 ;
    for(i = 0 ; i < state.size() ; i++)
        ans = (ans + dp[N][state[i]] ) % Mod ;
    return ans ;
}

int main(){
    int x ;
    while(cin>>N>>M){
        for(int i = 1 ; i <= N ; i++){
            cannot[i] = 0 ;
            for(int j = 1 ; j <= M ; j++){
                cin>>x ;
                if(x == 0)
                    cannot[i] |= (1<<(M-j)) ;
            }
        }
        cout<<DP()<<endl ;
    }
    return 0 ;
}







你可能感兴趣的:(POJ3254 Corn Fields(状态DP))