zoukankan      html  css  js  c++  java
  • [poj1185]炮兵阵地_状压dp

    炮兵阵地 poj-1185

        题目大意:给出n列m行,在其中添加炮兵,问最多能加的炮兵数。

        注释:n<=100,m<=10。然后只能在平原的地方建立炮兵。

          想法:第2到状压dp,++。这题显然是很经典的。设状态dp[i][j][k]表示第i行的状态为j,i-1行的状态为k的最多炮兵数。在转移时,枚举所有的合法炮兵排列(此处的合法数目是根据一行全为平原的时候能放置的合法炮兵数目),然后内层循环枚举dp[i-1]的i-1状态,进行特判更新即可。统计答案时,我们只需对于dp[n]的所有可能状态求最大值即可。

        最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    int dp[105][65][65];
    int cnt=0;
    int str[65];
    int sum[65];
    int map[110];
    char s[110][110];
    bool check(int x)//判断这个排列是否为普通的合法序列
    {
    	if(x&(x<<1)) return false;
    	if(x&(x<<2)) return false;
    	return true;
    }
    int getSum(int x)//当前状态的炮兵数目
    {
    	int ans=0;
    	while(x>0)
    	{
    		if(x&1) ans++;
    		x>>=1;
    	}
    	return ans;
    }
    void before_hand(int mid)//预处理出所有的可能合法炮兵状态,cnt统计状态数
    {
    	for(int i=0;i<(1<<mid);i++)
    	{
    		if(check(i))
    		{
    			str[cnt]=i;//str数组记录状态,dp中的j和k都是str数组的下标
    			sum[cnt]=getSum(i);
    			cnt++;
    		}
    	}
    }
    int main()
    {
    	int n,m;
    	scanf("%d%d",&n,&m);
    	memset(dp,-1,sizeof dp);
    	for(int i=0;i<n;i++)
    	{
    		for(int j=0;j<m;j++)
    		{
    			char a;
    			cin >> a;
    			if(a=='H') map[i]|=(1<<j);//统计每一行的不合法格子状态
    		}
    	}
    	before_hand(m);//其实可以不传参
    	for(int i=0;i<cnt;i++)
    	{
    		if(!(str[i]&map[0])) dp[0][0][i]=sum[i];//先处理出第一行的情况
    	}
    	for(int r=1;r<n;r++)//枚举行数
    	{
    		for(int i=0;i<cnt;i++)//枚举当前行的排列
    		{
    			if(str[i]&map[r]) continue;
    			for(int j=0;j<cnt;j++)//枚举上一行的排列情况
    			{
    				if(str[i]&str[j]) continue;
    				for(int k=0;k<cnt;k++)//枚举i-2行的排列情况
    				{
    					if(str[i]&str[k]) continue;
    					if(dp[r-1][k][j]==-1) continue;
    					dp[r][j][i]=max(dp[r][j][i],dp[r-1][k][j]+sum[i]);//更新即可
    				}
    			}
    		}
    	}
    	int ans=0;//统计答案
    	for(int i=0;i<cnt;i++)
    	{
    		for(int j=0;j<cnt;j++)
    		{
    			ans=max(ans,dp[n-1][i][j]);
    		}
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

         小结:这道题非常经典,我们有一种用空间换时间的办法就是4维dp。

          错误:卧槽!!一定牢记...判断时用的是运算符&而不是&&!!!

  • 相关阅读:
    多线程系列 线程池ThreadPool
    多线程系列 使用多线程的安全问题
    C#反射Assembly 详细说明
    Assembly(c#中简单说明[转]
    反射调用性能比较
    MFC控件GDI编程
    MFC控件第一讲.DC编程
    MFC原理第六讲.消息传递
    MFC原理第五讲.消息映射.以及如何添加消息
    MFC原理第四讲.动态创建机制
  • 原文地址:https://www.cnblogs.com/ShuraK/p/8566356.html
Copyright © 2011-2022 走看看