郑厂长系列故事——排兵布阵
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 2674 Accepted Submission(s): 952
Problem Description
郑厂长不是正厂长
也不是副厂长
他根本就不是厂长
事实上
他是带兵打仗的团长
一天,郑厂长带着他的军队来到了一个n*m的平原准备布阵。
根据以往的战斗经验,每个士兵可以攻击到并且只能攻击到与之曼哈顿距离为2的位置以及士兵本身所在的位置。当然,一个士兵不能站在另外一个士兵所能攻击到的位置,同时因为地形的原因平原上也不是每一个位置都可以安排士兵。
现在,已知n,m 以及平原阵地的具体地形,请你帮助郑厂长计算该阵地,最多能安排多少个士兵。
也不是副厂长
他根本就不是厂长
事实上
他是带兵打仗的团长
一天,郑厂长带着他的军队来到了一个n*m的平原准备布阵。
根据以往的战斗经验,每个士兵可以攻击到并且只能攻击到与之曼哈顿距离为2的位置以及士兵本身所在的位置。当然,一个士兵不能站在另外一个士兵所能攻击到的位置,同时因为地形的原因平原上也不是每一个位置都可以安排士兵。
现在,已知n,m 以及平原阵地的具体地形,请你帮助郑厂长计算该阵地,最多能安排多少个士兵。
Input
输入包含多组测试数据;
每组数据的第一行包含2个整数n和m (n <= 100, m <= 10 ),之间用空格隔开;
接下来的n行,每行m个数,表示n*m的矩形阵地,其中1表示该位置可以安排士兵,0表示该地形不允许安排士兵。
每组数据的第一行包含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
Source
Recommend
liuyiding
因为是中文题,这里就不给出题意解释了。
由题意我们可知对于我们任意一个士兵,在其曼哈顿距离为2的点上我们不能放置新的士兵。通过观察我们发现士兵的位置是斜向影响的,即横纵坐标值的和值为奇数的相互影响,为偶数的相互影响,而奇数和偶数之间没有影响关系。
那么我们可以将图像处理成这样(以样例为例)
0
0 0
0 0 0
0 0 0 0
0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0
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
0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0
其中然后我们的任务就是分别对红色和蓝色区域做状态压缩DP就行了,其中每一行的不能有两个连续的士兵,每一个士兵对于下一行的影响是当前位置以及之后两位的正下方即(P|P<<1|P<<2)。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m;
int mp[125][11];
int mp2[125];
int dp[125][1100];
int able[1024][1024];
int val[1024];
bool judge(int x)
{
int a=x&1;
x>>=1;
while(x)
{
int r=x&1;
if(a && r) return false;
a=r;
x>>=1;
}
return true;
}
void init()
{
for(int i=0;i<1024;i++)
{
int x=i,ans=0;
while(x)
{
if(x&1) ans++;
x>>=1;
}
val[i]=ans;
}
for(int i=0;i<1024;i++)
{
for(int j=0;j<1024;j++)
{
if(judge(j) && (i&j)==j) able[i][j]=1;
}
}
}
void solve(int x,int now)
{
//cout<<x<<" "<<now<<endl;
if(x>n+m) return;
if(dp[x][now]>=0) return;
dp[x][now]=0;
for(int i=0;i<(1<<m);i++)
{
if(!able[now][i]) continue;
//cout<<(i | (i<<1) | (i<<2))%(1<<m)<<endl;
int neww=~((~mp2[x+2]) | ((i | (i<<1) | (i<<2))%(1<<m)));
solve(x+2,neww);
dp[x][now]=max(dp[x+2][neww]+val[i],dp[x][now]);
}
}
int main()
{
init();
while(~scanf("%d%d",&n,&m))
{
if(n*m==0)
{
printf("0\n");
continue;
}
memset(mp,0,sizeof mp);
memset(mp2,0,sizeof mp2);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
scanf("%d",&mp[i+10][j]);
}
}
for(int i=10;i<n+m-1+10;i++)
{
for(int j=m-1;j>=0;j--)
{
mp2[i-10]<<=1;
mp2[i-10]|=mp[i-j][j];
}
}
//cout<<mp2[6]<<endl;
memset(dp,-1,sizeof dp);
solve(0,mp2[0]);
solve(1,mp2[1]);
printf("%d\n",dp[0][mp2[0]]+dp[1][mp2[1]]);
}
return 0;
}
/*
4 4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
*/