zoukankan      html  css  js  c++  java
  • P1879 [USACO06NOV] Corn Fields G

    题目描述

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

    遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是John不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。

    John想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)

    输入格式

    第一行:两个整数M和N,用空格隔开。

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

    输出格式

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

    输入输出样例

    输入 #1

    2 3
    1 1 1
    0 1 0

    输出 #1

    9

    一道入门的状压dp题,但对于我这种萌新还是太难了,所以写篇博客纪念一下。。。

    看到m的范围很小,我们就可以考虑对m进行状态压缩

    我们设 \(f[i][j]\) 表示第\(i\)行放置情况为\(j\)的方案数.

    我们就可以枚举所有的状态来进行转移

    也就是 \(f[i][j] += f[i-1][k]\)

    那怎么判断一个状态是否合法呢?

    首先,这一行不能选相邻的两列也就是 j & (j<<1) == 0, j & (j>>1) == 0

    并且还要与上一行的所选的不能有相邻的即 j & k == 0

    那么怎么判断这个状态选的土地是否都合法呢?

    我们可以预先处理每一行的初始状态,即对土地能不能选进行状态压缩。

    当 s[i] & j == 0 就代表j这个状态可能选了不肥沃的土地。(可以画个图了解一下)

    最终答案就是 \(\sum_{i=0}^{i< (1<<m)} f[n][i]\)

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int p = 1e8;
    int n,m,ans,x,base[20],f[15][35000],zhuangtai[20],map[20][20];
    inline int read()
    {
    	int s = 0, w = 1; char ch = getchar();
    	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9'){s = s * 10+ch -'0'; ch = getchar();}
    	return s * w; 
    }
    bool judge(int x)//判断x这个状态是否合法
    {
    	if(x & (x<<1)) return 0;
    	if(x & (x>>1)) return 0;
    	return 1;
    }
    int main()
    {
    	n = read(); m = read();
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= m; j++)
    		{
    			map[i][j] = read();
    		}
    	}
    	for(int i = 1; i <= n; i++)
    	{
    		for(int j = 1; j <= m; j++)
    		{
    			zhuangtai[i] = (zhuangtai[i]<<1) + map[i][j];//把一开始土地能不能选的情况进行状态压缩
    		}
    	}
    	base[0] = 1;
    	for(int i = 1; i <= m; i++) base[i] = base[i-1] * 2;
    	f[0][0] = 1;
    	for(int i = 1; i <= n; i++)
            {
    		for(int j = 0; j < base[m]; j++)
    		{
    			if(judge(j) && ((zhuangtai[i] & j) == j))//j这个状态不能选不肥沃的土地
    			{
    				for(int k = 0; k < base[m]; k++)
    				{
    					if(((j&k) == 0) && judge(k))
    					{
    						f[i][j] += f[i-1][k];//转移
    						f[i][j] %= p;
    					}
    				}
    			}
    		}
    	}
    	for(int i = 0; i < base[m]; i++) ans = (ans + f[n][i]) % p;
    	printf("%d\n",ans);
    	return 0;
    }
    
  • 相关阅读:
    【XSY2534】【CF835D】Palindromic characteristics 回文自动机
    启发式合并&线段树合并/分裂&treap合并&splay合并
    【XSY2534】【BZOJ4817】树点涂色 LCT 倍增 线段树 dfs序
    线性求逆元
    l1 和l2范数的真实意义
    方向导数及梯度
    大厂实习总结和反思
    高考报考以及心态调整健康贴士
    【骑士走棋盘】
    【老鼠走迷宫一】
  • 原文地址:https://www.cnblogs.com/genshy/p/13485231.html
Copyright © 2011-2022 走看看