状态压缩DP-Corn Fields(POJ 3254)

来源:互联网 发布:自动配餐王软件 编辑:程序博客网 时间:2024/05/21 21:50

Corn Fields
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 6384 Accepted: 3391

Description

Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and can't be planted. Canny FJ knows that the cows dislike eating close to each other, so when choosing which squares to plant, he avoids choosing squares that are adjacent; no two chosen squares share an edge. He has not yet made the final choice as to which squares to plant.

Being a very open-minded man, Farmer John wants to consider all possible options for how to choose the squares for planting. He is so open-minded that he considers choosing no squares as a valid option! Please help Farmer John determine the number of ways he can choose the squares to plant.

Input

Line 1: Two space-separated integers: M and N 
Lines 2..M+1: Line i+1 describes row i of the pasture with N space-separated integers indicating whether a square is fertile (1 for fertile, 0 for infertile)

Output

Line 1: One integer: the number of ways that FJ can choose the squares modulo 100,000,000.

Sample Input

2 31 1 10 1 0

Sample Output

9

Hint

Number the squares as follows:
1 2 3  4  

There are four ways to plant only on one squares (1, 2, 3, or 4), three ways to plant on two squares (13, 14, or 34), 1 way to plant on three squares (134), and one way to plant on no squares. 4+3+1+1=9.

Source

USACO 2006 November Gold

【题目大意】:

       一个M*N的矩阵有很多格子,每个格子上可以放牛(如果该格子为肥沃的才可以放牛,用1表示),也可以不放牛,现在在这块土地上放牛,要求两个相邻的方格不能同时放牛,即牛与牛不能相邻。问有多少种放牛方案(一头牛都不放也是一种方案)

 

【分析】:把每一行的状态用二进制的数表示,0表示不放牛,1表示放牛,对于第0行来讲,有很多种可行的放牛方式,每种状态用int Xi整形变量来表示,假设总共有10中可能的情况,那么可以定义一个二维数组DP[state][i],第一维表示行数,第二位表示状态,所以有DP[X1][0] = 1; DP[X2][0] = 1;等等。。。(代码中有优化,将DP数组的第二行为状态下标,而非状态本身)

 

那么基于第零行的情况,进入第一行,我们需要遍历上一行(第零行)的所有的情况,因此有第零行为X1状态时,得到10(假设值)种状态,为X2时得到10(假设值)种状态,依次类推,直到遍历完所有的情况。

 

显然,这是一个3个for嵌套的循环,第一个for表示遍历所有的层数(从第一层开始),第二个for表示遍历上层所有的情况,第三个for表示在上一层为特定状态下,该层可以有的状态数;

【状态表示】dp [i] [state]:在状态为state时,到第i行符合条件的可以放牛的方案数

【状态转移方程】dp [i] [state] =遍历dp[state'][i-1]state'为符合条件的所有状态)

相信非常清楚整个过程了吧,那开始写代码吧:

import java.io.BufferedInputStream;import java.util.Arrays;import java.util.Scanner;public class Main {private static final int MODULO = 100000000;private int dp[][];private int goodFroFarm[];private int isOK[];private int goodCount;private int allStatusCount;public Main(int M, int N) {allStatusCount = 1 << N;isOK = new int[M];goodFroFarm = new int[allStatusCount];}public static void main(String[] args) {Scanner cin = new Scanner(new BufferedInputStream(System.in));int M, N;M = cin.nextInt();N = cin.nextInt();Main ma = new Main(M, N);int bit;for (int i = 0; i < M; i++) {bit = 0;for (int j = 0; j < N; j++) {bit = bit << 1;bit = bit | cin.nextInt();}ma.isOK[i] = bit;}System.out.println(ma.getAllPossible());}private int getAllPossible() {// TODO Auto-generated method stub.prepareIt();// 先求出第零层的情况;for (int i = 0; i < goodCount; i++) {//看时候与肥沃的土地矛盾if((goodFroFarm[i] & isOK[0]) == goodFroFarm[i]){dp[0][i] = 1;}}// 从第一层的遍历for (int i = 1; i < isOK.length; i++) {//遍历上一层的所有的状态for(int j=0;j< goodCount;j++){if(dp[i-1][j] == 0){continue;}for(int k=0;k<goodCount;k++){//看是否满足肥沃的条件if((goodFroFarm[k] & isOK[i]) == goodFroFarm[k]){//看是否满足于上一层不相邻的情况if((goodFroFarm[k] & goodFroFarm[j]) == 0){dp[i][k] = dp[i-1][j] + dp[i][k];}}}}}int sum = 0;for(int k=0;k<goodCount;k++){if(dp[isOK.length-1][k] !=0){sum = sum + dp[isOK.length-1][k];}}return sum%MODULO;}private void prepareIt() {// TODO Auto-generated method stub// 取出所有的不能相邻的状态int count = 0;for (int i = 0; i < allStatusCount; i++) {if ((i & (i << 1)) == 0) {goodFroFarm[count] = i;count++;}}goodCount = count;dp = new int[isOK.length][count];for (int i = 0; i < dp.length; i++) {Arrays.fill(dp[i], 0);}}}





0 0
原创粉丝点击