POJ P3254 Java实现

参考文章:https://blog.csdn.net/mengxiang000000/article/details/51075506

题目链接:Corn Fields

对于给定的土地,令A为直到当前位置,牛可以放置的情况.A[i][j]为第i行第j状态.

A[i][j] += A[i-1][k].

因为  对于i行j列的A[i][j],需要考虑的是前一行的所有状态.

这里的j状态,是当前行占有的牛,作为二进制数字,转为整数时的值。

例如:

上面是草地分布,绿色为草地,黄色为不能长草的地.

假设计算出了A[2][10],A[2][2]的值,(实际上就是01010和00010两种放牛的状态)

那么对于第三行,

A[3][1],直到第三行最有一列放牛,牛可以放置的情况,

A[3][1] += A[2][2]+A[2][10]

同样的,第三行第三列和第五列放置牛的话(二进制状态为00101)

A[3][5] += A[2][2]+A[2][10].

所以,状态转移方程的形式就是:

A[i][j] += A[i-1][k].

但是不是所有土地都可以放牛,对于一块土地,牛能放置的方式,跟三个东西有关:

1.当前行的上一行,相同的列,有没有牛在吃草

2.当前行有没有相邻的两个牛一起吃草

3.当前行放置的牛所在的草地上是否有草

所以在写状态转移的时候,需要根据这三个条件去判断.

这里提供二进制的方式去判定三种状态.

情况1:前行的上一行,相同的列,有没有牛在吃草

假设绿色的是放牛的区域,黄色的是没有放牛的区域.

对比相邻两行的两种放置方式AB和CD.

将它们看成二进制数:

A:1100

B:0011

C:1011

D:1011

可以使用与运算来判断相邻两行同一列是否都放置了牛(颜色相同就是都放置了牛)

可以使用[A&B==0?符合规则:不符合规则]来进行放置是否符合规则的判断.

情况2当前行有没有相邻的两个牛一起吃草

考虑A和C两种情况.(先忽略蓝色的格子)

A:1011

C:1010

考虑以下左移操作.

所以就和上图的B和D一样,在进行左移后,AB在同一列有相同的绿色格子,但是CD在同一列没有相同的绿色格子.

如果二进制数有两位连续相同的1的话,将二进制左移一位后,和它本身进行与操作,一定会有一位是1.

所以对于数字M,判断是否有连续的1,可以使用[(M<<1)&M ==1?包含连续:不含连续]来判断.

情况3当前行放置的牛所在的草地上是否有草

在放置牛的时候,如何保证牛放置的地方一定就是有草的?

上图草地为11010

现在有三种牛的放置情况

A:10101

B:11000

C:11010

直观去看,只有绿色草地能放牛,所以A放置方式不符合规则,BC放置方式符合规则.

符合规则说明牛的位置必须是草,所以仍旧可以利用与运算.

加入需要判断的数字为A,比较对象为B:

[A&B==A?符合条件:不符合条件]

使用它可以判断以当前方式放牛是否符合土地规则.

以上就是分析,下面是JAVA代码.

在代码中,动态规划数组初始化我增加了第0行,实际计算是从dp[1][0]~dp[n][1<<m]的.

注意,第二维是将土地二进制转为十进制后的情况枚举.

为何要初始化dp[0][0]=1?

因为题目中说即使不放牛,也算一种方式.所以即使是整行都是0,也算一种情况.

为什么需要第0行?

因为需要用它来计算起始行(第一行)的状态.第0行全部为0,所以第0行是不会影响第一行的结果的.

如果不容易去理解,也可以手动去计算以下第一行的状态作为初始状态.

package judge._open_judge.P3254_CornFields;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main2 {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int m = Integer.parseInt(st.nextToken());
        int n = Integer.parseInt(st.nextToken());
        int[] arrays = new int[m+1];
        int mod = 100000000;
        int sum;
        for(int i = 1;i<=m;i++){
            st = new StringTokenizer(br.readLine());
            sum = 0;
            for(int j = 0;j<n;j++){
                sum+=Math.pow(2,n-j-1)*Integer.parseInt(st.nextToken());
            }
            arrays[i] = sum;
        }
        long[][] dp = new long[m+1][(1<<n)];
        dp[0][0] = 1;
        for(int i = 1;i<=m;i++){
            //当前行的🐂的状态
            for(int j = 0;j<(1<<n);j++){
                //前一行的🐂的状态
                //🌽种在土地上,牛只能在土地上吃玉米
                if((j&arrays[i])!=j){
                    continue;
                }
                //🐂左右不能相邻
                if((j&(j<<1))!=0){
                    continue;
                }
                for(int k = 0;k<(1<<n);k++){
                    //🐂上下不能相邻
                    if((j&k)!=0){
                        continue;
                    }
                    //当前行的状态和=当前行的状态+前一行的状态和
                    dp[i][j] += dp[i-1][k];
                    dp[i][j] = dp[i][j]%mod;
                }
            }
        }
        long result = 0;
        for(int i = 0;i<(1<<n);i++){
            result+=dp[m][i];
            result %= mod;
        }
        System.out.println(result);
    }
}

posted @ 2021-04-30 17:18  Monstro  阅读(72)  评论(0)    收藏  举报