zoukankan      html  css  js  c++  java
  • [NOI2001]炮兵阵地

    洛咕

    题意:司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个(N*M)((N<=10,M<=100))的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图.在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:

    如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响.现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队.

    分析:状压DP一般都是以一行为一个状态,所以首先可以预处理出同一行任意相邻两个1之间的距离大于等于3(即保证不会出现同一行的打自己人情况)的合法状态,存到集合S中.

    (f[i][j][k])表示前i行,第i行状态为S[j],第i-1行状态为S[k]的合法方案数.(因为第i行的状态同时受i-1和i-2两行的影响,所以要开出两维来存状态,方便我们转移)(不能让j,k两维直接存状态,空间会爆,除非你第一维用滚动数组)

    (count(S[j]))表示S[j]这个状态有多少位是1,(check(i,S[j]))表示S[j]这个状态上为1的位对应到第i行是否全都是平原(即保证布置的炮兵位置合法)

    如果(check(i,S[j])=1)(check(i-1,S[k])=1)(S[j])&(S[k]=0)(S[j])&(S[l]=0),(f[i][j][k]=max(f[i][j][k],f[i-1][k][l]+count(S[j])))

    目标:如果(check(n,S[i])=1)(check(n-1,S[j])=1)(S[i])&(S[j]=1),(ans=max(f[n][i][j]))

    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    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;
    }
    const int N=1050;
    int n,m,sum;
    int a[105][15],S[N],f[105][405][405];
    inline bool check(int x,int y){//状态y在第x行是否合法
        if(!y)return true;
        for(int i=0;i<m;i++)
    	if(((y>>i)&1)&&(a[x][m-i]==2))return false;
        return true;
    }
    inline int count(int x){//计算x这个状态有多少位1
        int num=0;
        for(int i=0;i<=11;i++)
    		if((x>>i)&1)num++;
        return num;
    }
    int main(){
        n=read(),m=read();
        for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++){
    	    	char ch;cin>>ch;
    	    	if(ch=='P')a[i][j]=1;//平原
    	    	else a[i][j]=2;//山丘
    		}
    //预处理任意相邻两个1之间的距离大于等于3的合法状态
        for(int i=0;i<(1<<m);i++){
    		int last=-1,bj=1;
    		for(int j=0;j<m;j++){
    	    	if((i>>j)&1){
    				if(last==-1)last=j;
    				else if(j-last<3){bj=0;break;}
    				else last=j;
    	    	}
    		}
    		if(bj)S[++sum]=i;
        }
        for(int i=1;i<=n;i++){
    		for(int j=1;j<=sum;j++){
    	    	if(!check(i,S[j]))continue;
    	    	for(int k=1;k<=sum;k++){
    				if(!check(i-1,S[k])||(S[j]&S[k]))continue;
    				for(int l=1;l<=sum;l++){
    		    		if((S[j]&S[l]))continue;
    		    		f[i][j][k]=max(f[i][j][k],f[i-1][k][l]+count(S[j]));
    				}
    	    	}
    		}
        }
        int ans=0;
        for(int i=1;i<=sum;i++){
    		if(check(n,S[i])==0)continue;
    		for(int j=1;j<=sum;j++){
    	    	if(check(n-1,S[j])==0||(S[i]&S[j]))continue;
    	    	ans=max(ans,f[n][i][j]);
    		}
        }
        printf("%d
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    JZOJ 3034. 【NOIP2012模拟10.17】独立集
    JZOJ 3035. 【NOIP2012模拟10.17】铁轨
    JZOJ 1259. 牛棚安排
    数位DP JZOJ 3316. 非回文数字
    JZOJ 3046. 游戏
    JZOJ 3013. 填充棋盘
    debian 安装oracle提供的java8
    java 汉字转拼音 PinYin4j
    debian ssh设置root权限登陆 Permission denied, please try again
    java并发下订单生成策略
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10958329.html
Copyright © 2011-2022 走看看