郑厂长系列故事——排兵布阵
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 3671 Accepted Submission(s): 1261
Problem 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
题意:中文题略。
思路:
先预处理出同行的合法状态,然后状态压缩的过程中对不合法状态进行剪枝,这样枚举这一行、上一行、上上行的状态进行相应的状态转移,实际复杂度非常低。
代码:
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<string>
#include<queue>
#include<vector>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(register int i=(a);i<=(b);++i)
using namespace std;
const int maxn=12;
const ll mo=1e8;
int n,m,k,mm;
int a[110][maxn];
int tmp[110];
int zt[110][1026],cnt;
int dp[2][1026][1026];
int c[1026];
int cal(int x)
{
int sum=0;
while(x)
{
x&=(x-1);
sum++;
}
return sum;
}
void init()
{
rep(i,1,n)
{
zt[i][0]=0;
rep(j,0,mm)
if((j|tmp[i])==j){
int x=j^tmp[i];
if(x&(x>>2)) continue;
if(x&(x<<2)) continue;
zt[i][++zt[i][0]]=j;
if(i==1) dp[i][0][j]=c[x];
//if(i==2)cout<<j<<" "<<tmp[i]<<" "<<x<<endl;
}
}
}
int main()
{
rep(i,0,1024) c[i]=cal(i);
int T,cas=1;
while(scanf("%d%d",&n,&m)!=EOF)
{
mm=(1<<m)-1;
rep(i,1,n)
{
tmp[i]=0;
rep(j,0,m-1)
{
int x;
scanf("%d",&x);
if(!x) tmp[i]|=(1<<j);
}
}
memset(dp,-1,sizeof(dp));
init();
zt[0][0]=1;
zt[0][1]=0;
rep(i,2,n)
{
int od=((i-1)&1),nw=od^1;
memset(dp[nw],-1,sizeof(dp[nw]));
rep(jj,1,zt[i-2][0])
{
int j=zt[i-2][jj]^tmp[i-2];
rep(kk,1,zt[i-1][0])
{
int k=zt[i-1][kk]^tmp[i-1];
if(dp[od][j|tmp[i-2]][k|tmp[i-1]]==-1) continue;
if(j&(k>>1)) continue;
if(j&(k<<1)) continue;
rep(tt,1,zt[i][0])
{
int t=zt[i][tt]^tmp[i];
if(t&j) continue;
if(t&(k>>1)) continue;
if(t&(k<<1)) continue;
int j1=j|tmp[i-2],k1=k|tmp[i-1],t1=t|tmp[i];
//cout<<tt<<" "<<tmp[i]<<" "<<i<<" "<<t<<" "<<c[t]<<" * ";
dp[nw][k1][t1]=max(dp[nw][k1][t1],dp[od][j1][k1]+c[t]);
}
}
}
}
int ans=0,t=(n&1);
rep(i,0,mm)
rep(j,0,mm)
ans=max(ans,dp[t][i][j]);
printf("%d\n",ans);
}
return 0;
}