HDU 4539 郑厂长系列故事――排兵布阵(状压DP+滚动数组->求可放棋子最大数量)

郑厂长系列故事――排兵布阵
Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Description

  郑厂长不是正厂长 
  也不是副厂长 
  他根本就不是厂长 
  事实上 
  他是带兵打仗的团长 

  一天,郑厂长带着他的军队来到了一个n*m的平原准备布阵。 
  根据以往的战斗经验,每个士兵可以攻击到并且只能攻击到与之曼哈顿距离为2的位置以及士兵本身所在的位置。当然,一个士兵不能站在另外一个士兵所能攻击到的位置,同时因为地形的原因平原上也不是每一个位置都可以安排士兵。 
  现在,已知n,m 以及平原阵地的具体地形,请你帮助郑厂长计算该阵地,最多能安排多少个士兵。 

Input

输入包含多组测试数据; 
每组数据的第一行包含2个整数n和m (n <= 100, m <= 10 ),之间用空格隔开; 
接下来的n行,每行m个数,表示n*m的矩形阵地,其中1表示该位置可以安排士兵,0表示该地形不允许安排士兵。 

Output

请为每组数据计算并输出最多能安排的士兵数量,每组数据输出一行。 

Sample Input

6 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 1 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0

Sample Output

2


状压DP。。。。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
int dp[2][1<<10][1<<10], save[1<<11];
int get(int x)
{
    int res=0;
    while(x>0)
    {
        if(x&1)
            res++;
        x>>=1;
    }
    return res;
}


int main()
{
    int n, m;
    while(scanf("%d %d", &n, &m)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        memset(save,0,sizeof(save));
        int num=1<<m;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<m;j++)
            {
                int k;
                scanf("%d", &k);
                if(!k)
                    save[i]|=(1<<j);
            }
        }
        for(int i=0;i<num;i++)
        {
            if(((i<<2)&i)||(i&save[1]))
                continue;
            dp[1][i][0]=get(i);
        }
        int x1=1, x2=1;
        for(int i=2;i<=n;i++)
        {
            x2=x1^1;
            memset(dp[x2],0,sizeof(dp[x2]));
            for(int j=0;j<num;j++)
            {
                if((j&(j<<2))||(j&save[i]))
                    continue;
                for(int k=0;k<num;k++)
                {
                    if((k&(k<<2))||(k&save[i-1])||(j&(k<<1))||(j&(k>>1)))
                        continue;
                    dp[x2][j][k]=get(j);
                    int cnt=0;
                    for(int p=0;p<num;p++)
                    {
                        if((p&p<<2)||(p&save[i-2])||(p&(k<<1))||(p&(k>>1))||(p&j))
                            continue;
                        cnt=max(cnt,dp[x1][k][p]);
                    }
                    dp[x2][j][k]+=cnt;
                }
            }
            x1=x2;
        }
        int ans=0;
        for(int i=0;i<num;i++)
        {
            for(int j=0;j<num;j++)
            {
                ans=max(dp[x2][i][j],ans);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}



态压缩dp.


因为当前位置与前两行有关,所以把相邻两行作为二维状态,枚举第i-2行即可得到第i行的状态。


记状态dp[][i][j]表示当前行状态为i,前一行状态为j时,最多能放的士兵个数。


dp[][i][j]=Cal(i)+max(dp[][j][k]);








<span style="font-size:14px;">#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF 0x1f1f1f1f
#define PI acos(-1.0)
#define ll __int64
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;


/*
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
*/
#define Maxn 110
int dp[2][1<<10][1<<10];
int save[Maxn];


int Cal(int st) //统计1的个数
{
   int res=0;
   while(st)
   {
      if(st&1)
         res++;
      st>>=1;
   }
   return res;
}


int main()
{
   int n,m,tmp;


   while(~scanf("%d%d",&n,&m))
   {
      for(int i=1;i<=n;i++)
      {
         save[i]=0;
         for(int j=0;j<m;j++)
         {
            scanf("%d",&tmp);
            if(!tmp) //0表示不能放,把它作为1考虑 能放作为0考虑
               save[i]|=(1<<j);
         }
      }
      memset(dp,0,sizeof(dp));
      int lim=1<<m;
      for(int i=0;i<lim;i++)
      {
         if((i&(i<<2))||(i&save[1])) //该状态满足
            continue;
         dp[1][i][0]=Cal(i); //只用记住一个状态0,表示一个标志
      }


      int la=1,cur;
      for(int i=2;i<=n;i++)
      {
         cur=la^1;
        // memset(dp[cur],0,sizeof(dp[cur]));
         for(int j=0;j<lim;j++)
         {
            if((j&(j<<2))||(j&save[i])) //该状态满足
               continue;
            for(int k=0;k<lim;k++)
            {
               if((k&(k<<2))||(k&save[i-1])) //该状态满足当前行的要求
                  continue;
               if(j&(k<<1))
                  continue;
               if(j&(k>>1))  //注意要考虑 左移右移两种情况
                  continue;
               dp[cur][j][k]=Cal(j); //该行1的个数
               int Max=0;
               for(int p=0;p<lim;p++)
               {
                  if((p&(p<<2))||(p&save[i-2]))
                     continue;
                  if((k&(p<<1))||(j&p)) //i-2行与i-1行的关系
                     continue;
                  if(k&(p>>1)) //i-2行与i行的关系
                     continue;


                  Max=max(Max,dp[la][k][p]);
               }
               dp[cur][j][k]+=Max;
            }
         }
         la=cur;
      }
      int ans=0;
      for(int i=0;i<lim;i++)
         for(int j=0;j<lim;j++) //注意不能构成关系的全为0
            ans=max(ans,dp[cur][i][j]);
      printf("%d\n",ans);




   }
   return 0;
}


是由十九世纪的赫尔曼·闵可夫斯基所创词汇 ,是种使用在几何度量空间的几何学用语,用以标明两个点在标准坐标系上的绝对轴距总和。

基本信息

  • 中文名称

    曼哈顿距离

  • 所创人

    赫尔曼·闵可夫斯基

 
  • 属    于

    使用在几何度量空间的几何学用语

  • 类    别

    词汇 

折叠编辑本段​简介

折叠名词解释

出租车几何或曼哈顿距离(Manhattan Distance)是由十九世纪的赫尔曼·闵可夫斯基所创词汇 ,是种使用在几何度量空间的几何学用语,用以标明两个点在标准坐标系上的绝对轴距总和。图中红线代表曼哈顿距离,绿色代表欧氏距离,也就是直线距离,而蓝色和黄色代表等价的曼哈顿距离。曼哈顿距离--两点在南北方向上的距离加上在东西方向上的距离,即d(i,j)=|xi-xj|+|yi-yj|。对于一个具有正南正北、正东正西方向规则布局的城镇街道,从一点到达另一点的距离正是在南北方向上旅行的距离加上在东西方向上旅行的距离因此曼哈顿距离又称为出租车距离,曼哈顿距离不是距离不变量,当坐标轴变动时,点间的距离就会不同。曼哈顿距离示意图在早期的计算机图形学中,屏幕是由像素构成,是整数,点的坐标也一般是整数,原因是浮点运算很昂贵,很慢而且有误差,如果直接使用AB的欧氏距离(欧几里德距离:在二维和三维空间中的欧氏距离的就是两点之间的距离距离),则必须要进行浮点运算,如果使用AC和CB,则只要计算加减法即可,这就大大提高了运算速度,而且不管累计运算多少次,都不会有误差。

折叠详细资料

我们可以定义曼哈顿距离的正式意义为L1-距离或城市区块距离,也就是在欧几里德空间的固定直角坐标系上两点所形成的线段对轴产生的投影的距离总和。

例如在平面上,坐标(x1, y1)的i点与坐标(x2, y2)的j点的曼哈顿距离为:

d(i,j)=|X1-X2|+|Y1-Y2|.

要注意的是,曼哈顿距离依赖坐标系统的转度,而非系统在坐标轴上的平移或映射。

曼哈顿距离的命名原因是从规划为方型建筑区块的城市(如曼哈顿)间,最短的行车路径而来(忽略曼哈顿的单向车道以及只存在于3、14大道的斜向车道)。任何往东三区块、往北六区块的的路径一定最少要走九区块,没有其他捷径。

出租车几何学满足除了SAS全等定理之外的希伯特定理,SAS全等指任两个三角型两个边与它们的夹角均分别对应相等,则这两个三角型全等。

在出租车几何学中,一个圆是由从圆心向各个固定曼哈顿距离标示出来的点围成的区域。因此这种圆其实就是旋转了45度的正方形。如果有一群圆,任两圆皆相交,则整群圆必在某点相交;因此曼哈顿距离会形成一个超凸度量空间(Injective metric space)。对一个半径为r 的圆来说,这个正方形的圆每边长√2r。此'"圆"的半径r对切比雪夫距离 (L∞ 空间)的二维平面来说,也是一个对座标轴来说边长为2r的正方形,因此二维切比雪夫距离可视为等同于旋转且放大过的二维曼哈顿距离。然而这种介于L1与L∞的相等关系并不能延伸到更高的维度。

折叠编辑本段数学性质

非负性:d(i,j)≥0 距离是一个非负的数值

同一性:d(i,i)= 0 对象到自身的距离为0

对称性:d(i,j)= d(j,i)距离是一个对称函数

三角不等式:d(i,j)≤d(i,k)+d(k,j)从对象i到对象j的直接距离不会大于途经的任何其他对象k的距离

折叠编辑本段计量方法

在西洋棋里,车(城堡)是以曼哈顿距离来计算棋盘 格上的距离;而王(国王)与后(皇后)使用切比雪夫距离,象(主教)则是用转了45度的曼哈顿距离来算(在同色的格子上),也就是说它以斜线为行走路径。只有国王需要一步一步走的方式移动,皇后、主教与城堡可以在一或两次移动走到任何一格(在没有阻碍物的情况下,且主教忽略它不能走到的另一类颜色)。

图为曼哈顿与欧几里德距离: 红、蓝与黄线分别表示所有曼哈顿距离都拥有一样长度(12),而绿线表示欧几里德距离有6×√2 ≈ 8.48的长度。

曼哈顿距离--两点在南北方向上的距离加上在东西方向上的距离,即d(i,j)=|xi-xj|+|yi-yj|。对于一个具有正南正北、正东正西方向规则布局的城镇街道,从一点到达另一点的距离正是在南北方向上旅行的距离加上在东西方向上旅行的距离因此曼哈顿距离又称为出租车距离,曼哈顿距离不是距离不变量,当坐标轴变动时,点间的距离就会不同。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值