zoukankan      html  css  js  c++  java
  • 【ybtoj】【状压dp】种植方案

    题意

    题目描述

    农场主新买了一块长方形的新牧场,这块牧场被划分成m行n列,每一格都是一块正方形的土地。农场主打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。

    遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是农场主不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。 如果不考虑草地的总块数,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)

    输入格式

    第1行:两个整数 m和 n,用空格隔开。
    第2到第m+1行:每行包含 n个用空格隔开的整数,描述了每块土地的状态。第i+1行描述了第i行的土地,所有整数均为 0或 1,1表示这块土地足够肥沃, 0则表示这块土地不适合种草。

    输出格式

    一个整数,即牧场分配总方案数除以1e8的余数。

    样例

    输入样例

    2 3  
    1 1 1  
    0 1 0
    

    输出样例

    9
    

    数据范围与提示

    对于100%的数据,满足n,m ∈[1,12]。

    分析

    十分经典的状压dp,很好想但是涉及一些状压dp的细节和简单优化,类似于模板,需要研究透彻!

    优化:

    1. 用jud数组先预处理出第 i 行 j 的状态可不可行,循环内就可以O(1)判断
    2. 由于本身每一行有一些位置不能放,即有一些状态不可行,可以给每个合法的状态一个编号,让编号作为第二维,可以减少一些空间和时间(本代码中没有涉及)

    注意事项

    代码中关键部分和第一次的错误都已经用注释标注出来!ovo

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int INF = 0x3f3f3f3f,mod = 1e8;
    int dp[13][1<<13];//dp[i][j]表示第i行状态为j时的方案数 
    int n,m;
    bool jud[13][1<<13];
    int a[13][13];
    int main()
    {
    	scanf("%d%d",&m,&n);
    	for(int i=1;i<=m;i++)
    		for(int j=1;j<=n;j++)
    			scanf("%d",&a[i][j]);
    	//预处理 
    	for(int i=1;i<=m;i++)//第i行 
    		for(int j=0;j<(1<<n);j++)//状态为j 
    			{
    				if(j&(j>>1))//如果有相邻土地被用 
    				{	
    					jud[i][j]=1;
    					continue;
    				}
    				for(int k=1;k<=n;k++)	
    					if( (j&(1<<(k-1)))&& !a[i][n-k+1])//如果有不能种的地方种了东西 
    					{
    						jud[i][j]=1;
    						break;
    					}
    			}
    	/*
    	for(int i=0;i<(1<<n);i++)
    		dp[1][i]=1;//初始化第1行任何状态都为1 
    	//注意:原来初始化第0行状态都为1,同时i从1开始枚举,这样是不对的 
    	*/
      	//
    	dp[0][0]=1;//初始化第0行为0状态,可以转移到第1行任何状态且不重复,和上面的初始化等效 
    	for(int i=1;i<=m;i++)//根据初始化注意i从几开始枚举 
    		for(int j=0;j<(1<<n);j++)//枚举当前行状态 
    		{
    			if(jud[i][j]) continue;
    			for(int k=0;k<(1<<n);k++)//枚举上一行状态 
    			{
    				if(jud[i-1][k]||(k&j)) continue;
    				dp[i][j]=((ll)dp[i][j]+dp[i-1][k])%mod;
    			}
    		}
    	ll ans=0;
    	for(int i=0;i<(1<<n);i++)
    	{
    		if(jud[m][i]) continue;//注意这里的判断,如果m==1时不加会错 
    		ans=(ans+dp[m][i])%mod;
    	}
    	printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    非递归的中序遍历(inorder)树 leetcode 94
    基于二叉树的抢劫问题 leetcode337
    查询二叉树的公共父结点 leetcode 236
    链表的无锁操作 (JAVA)
    kexec 内核快速启动流程分析
    最近几天严重营养不良。。。
    Better Me
    《大四上寒假总结》--3.10
    《计算机网络》学习总结
    记录
  • 原文地址:https://www.cnblogs.com/conprour/p/15045705.html
Copyright © 2011-2022 走看看