状态压缩.java

package A类有价值的回顾的;
//http://www.tuicool.com/articles/JVzMVj

import java.util.Scanner;


//如果一道题前期你没有明确的思路,说明你已经输了,而且后期你脱的时间越长,输的越多
//不要纠结在毫不值得的地方
public class 状态压缩 {
    public static int mod = 100000000;

    public static void main (String[] args){

        Scanner sc = new Scanner(System.in);
        int M = sc.nextInt();
        int N = sc.nextInt();//每一行都变成一个二进制数来表示
        int[] a = new int[M];//这里输入的是本身条件的限制
        boolean[] c = new boolean[1<<N];//记录第i种方案是否可行    这里除去与a[]中矛盾的剩下的就是所有可行的方案
                                //但是相比于前期的求出所有可行方案,不如在后期判断的时候加进去限制条件,固定的思维模式在一定条件下是可以的,你要做到的是利益的最大化,而不是你内心的成就感
        int[][] dp = new int[M][1<<N];

        //输入条件限制
        for(int i=0;i<M;i++){//无论从第几个开始都可以做,那么就不要较劲非要找到一种统一方法,把你的劲使到最优的地方去
            for(int j=0;j<N;j++){
                int b = sc.nextInt();
                if(b == 1)
                    a[i] += 1<<(N-j-1);
            }
        }

        //找到一行中所有左右不相邻的方案,对于每一行都适用  
        for(int i=0;i<c.length;i++){
            if((i&i<<1) == 0)
                c[i] = true;
        }

        //初始化第零行
        for(int i=0;i<c.length;i++){
            if(c[i] == true &&(~a[0]&i) == 0)//记住1&1才有判断性
                                  //里面的()必须要加,等于1说明前后相邻且为1 !!!记住:!=1的反面不是==0
                dp[0][i] = 1;
        }

        //往接下来的第j行,本行的i方案,有几种
        for(int j=1;j<M;j++){
            for(int i=0;i<(1<<N);i++){
                for(int prei=0;prei<(1<<N);prei++){//prei指的是前一行的i方案
                    //前后不相邻 左右不相邻 条件允许
                    if((i&prei)==0 && (~a[j]&i) == 0 && c[i] == true){
                        dp[j][i] = (dp[j][i] + dp[j-1][prei])%mod;因为这里只与前一个有关系 ,可以用滚动数组
                    }
                }
            }
        }

        //计算最后一次的
        int sum = 0;
        for(int i=0;i<(N<<1);i++){
            sum = (sum + dp[M-1][i])%mod;
    }
    System.out.println(sum);
}
}
/*
 * 题目大意: 农夫有一块地,被划分为m行n列大小相等的格子,其中一些格子是可以放牧的(用1标记),农夫可以在这些格子里放牛,
  其他格子则不能放牛(用0标记),并且要求不可以使相邻格子都有牛。现在输入数据给出这块地的大小及可否放牧的情况,
  求该农夫有多少种放牧方案可以选择(注意:任何格子都不放也是一种选择,不要忘记考虑!

Sample Input
2 3
1 1 1
0 1 0

Sample Output
9

 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值