Time Limit: 10000/5000 MS (Java/Others)
Memory Limit: 65535/32768 K (Java/Others)
题目链接http://acm.hdu.edu.cn/showproblem.php?pid=4539
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
emmm,和POJ的1185炮兵阵地一样的解法,具体解析请看我的状压DP(2):
https://blog.youkuaiyun.com/qq_43906000/article/details/90905180
但稍微有点不同的就是加了个曼哈顿距离,其实也就是走两步能够达到的,比如:
1 0 是放不了的,1 0 1也是放不了的。那么我们只需要在炮兵阵营的基础上删掉
0 1
一步的情况,然后加个对角线的情况就好了:
if (((v[j]<<1)&v[k]) || ((v[j]>>1)&v[k]))
这个就是对角线的情况了。。。没什么难的。。。其他的就和炮兵阵地一样了。。。
那么这题也就OK了,只不过要注意多组输入。。我就是多组的问题WA了一次又T了一次。。。
以下是AC代码:
#include <bits/stdc++.h>
using namespace std;
#define fr(i,n) for (int i=0; i<n; i++)
int a[105][12],v[172],num[172],ans=0;
int cnt=0,n,m,dp[105][172][172];
int ok(int r,int s);
int main() {
while (scanf ("%d%d",&n,&m)!=EOF) {
cnt=0;ans=0;
memset(dp,0,sizeof(dp));
memset(v,0,sizeof(v));
memset(num,0,sizeof(num));
fr(i,(1<<m)) if ((i&(i<<2))==0) {
v[cnt++]=i;
int sum=0;
fr(j,m) if (i&(1<<j)) sum++;
num[cnt-1]=sum;
}
fr(i,n) fr(j,m) scanf ("%d",&a[i][j]);
fr(i,n) {
fr(j,cnt) {
if (!ok(i,v[j])) continue;
if (i==0) {
dp[i][j][0]=num[j];
continue;
}
if (i==1) {
fr(k,cnt) {
if (((v[j]<<1)&v[k]) || ((v[j]>>1)&v[k])) continue;
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][0]+num[j]);
}
continue;
}
fr(k,cnt) {
if (((v[j]<<1)&v[k]) || ((v[j]>>1)&v[k])) continue;
fr(g,cnt) {
if (v[j]&v[g]) continue;
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][g]+num[j]);
}
}
}
}
fr(i,cnt) fr(j,cnt) ans=max(ans,dp[n-1][i][j]);
printf ("%d\n",ans);
}
return 0;
}
int ok(int r,int s) {
fr(i,m) if ((s&(1<<i)) && !a[r][i]) return 0;
return 1;
}