zoukankan      html  css  js  c++  java
  • POJ 3254 Corn Fields 状态压缩DP (C++/Java)

    http://poj.org/problem?

    id=3254

    题目大意:

    一个农民有n行m列的地方,每一个格子用1代表能够种草地,而0不能够。放牛仅仅能在有草地的。可是相邻的草地不能同一时候放牛。 问总共同拥有多少种方法。

    思路:

    状态压缩的DP。

    能够用二进制数字来表示放牧情况并推断该状态是否满足条件。

    这题的限制条件有两个:

    1.草地限制。

    2.相邻限制。


    对于草地限制,由于输入的时候1是能够种草地的。

    以”11110“草地分析,就仅仅有最后一个是不能够种草的。

    取反后得00001  。(为啥取反?不取反能够举出反例的)

    如果有个状态10101 这个不相邻,可是10101  & 00001 !=0 表示有冲突。


    对于相邻限制,又分为同一行的限制和上下两行的限制。

    同一行限制能够一開始把相邻的情况都去掉,符合的存进数组,有助于降低状态数。 这样这个也攻克了。

    上下两行相与就可以。

    如(如果均可种草)

    10101 & 00100!=0 也是有冲突的。


    OK上代码。


    C++:

    #include<cstdio>
    #include<cstring>
    const int mod = 100000000;
    const int MAXN = 1 << 12;
    int map[20], status[MAXN], dp[20][MAXN];
    int len;
    
    int main()
    {
    	int n, m;
    	while (~scanf("%d%d", &n, &m))
    	{
    		for (int i = 0; i < n; i++)
    		{
    			for (int j = 0; j < m; j++)
    			{
    				int temp;
    				scanf("%d", &temp);
    				if (!temp)
    					map[i] = map[i] | (1 << (m - j - 1));
    			}
    		}
    		
    		len = 0;
    		int tot = 1 << m;
    		//全部状态
    		for (int i = 0; i < tot; i++)
    		{
    			//左移右移均可
    			if ((i &(i >> 1)) == 0)  status[len++] = i;
    		}
    		//初始化第一行
    		memset(dp, 0, sizeof(dp));
    		for (int i = 0; i <len ; i++)
    		{
    			if ((status[i] & map[0]) == 0)
    				dp[0][i] = 1;
    		}
    
    		for (int i = 1; i < n; i++)
    		{
    			for (int j = 0; j < len; j++)
    			{
    				if ((status[j] & map[i-1]) != 0) continue;
    				for (int k = 0; k < len; k++)
    				{
    					if ((status[k] & map[i]) != 0)  continue;
    					if ((status[k] & status[j]) != 0)  continue;
    					dp[i][k] = (dp[i][k] +dp[i - 1][j] )% mod;
    				}
    			}
    		}
    		int ans = 0;
    		for (int i = 0; i < len; i++)
    			ans = (ans + dp[n - 1][i]) % mod;
    		printf("%d
    ", ans);
    	}
    	return 0;
    }




    JAVA:


    import java.util.Scanner;
    
    public class Main {
    
    	final static int mod = 100000000;
    	final static int MAXN = 1 << 12;
    	static int[] map = new int[20];
    	static int[] status = new int[MAXN];
    	static int[][] dp = new int[20][MAXN];
    	static int len;
    
    	public static void main(String[] args) {
    		Scanner cin = new Scanner(System.in);
    		int n, m;
    		while (cin.hasNext()) {
    			n = cin.nextInt();
    			m = cin.nextInt();
    			init(n,m);
    
    			for (int i = 0; i < n; i++)
    				for (int j = 0; j < m; j++) {
    					int temp = cin.nextInt();
    					if (temp ==0)
    						map[i] = (map[i] | (1 << (m - j - 1)));
    				}
    
    			int tot = 1 << m;
    			len = 0;
    			for (int i = 0; i < tot; i++)
    				if ((i & (i << 1)) == 0) {
    					status[len++] = i;
    				}
    
    			for (int i = 0; i < len; i++) {
    				if ((map[0] & status[i]) == 0)
    					dp[0][i] = 1;
    			}
    
    			for (int i = 1; i < n; i++) {
    				for (int j = 0; j < len; j++) {
    					if ((map[i - 1] & status[j]) != 0)
    						continue;
    					for (int k = 0; k < len; k++) {
    						if ((map[i] & status[k]) != 0)
    							continue;
    						if ((status[j] & status[k]) != 0)
    							continue;
    						dp[i][k] = (dp[i][k] + dp[i - 1][j]) % mod;
    					}
    				}
    			}
    			int ans = 0;
    			for (int i = 0; i < len; i++) {
    				ans = (ans + dp[n - 1][i]) % mod;
    			}
    			System.out.println(ans);
    		}
    	}
    
    	public static void init(int n,int m)
    	{
    		int tot=1<<m;
    		for(int i=0;i<n;i++)
    		{	
    			map[i]=0;
    			for(int j=0;j<tot;j++)
    				dp[i][j]=0;
    		}
    	
    		
    	}
    }
    


  • 相关阅读:
    用同余理解补码
    objenesis
    spring 事务处理
    SOCKS5 协议解析
    WebSocket 的鉴权授权方案
    加密解密基础问题:字节数组和16进制字符串的相互转换
    主机字节序 与 网络字节序
    RSA 理论
    分类算法----k近邻算法
    R语言统计分析应用与SAS、SPSS的比较
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/7055454.html
Copyright © 2011-2022 走看看