您的位置:首页 > 其它

HDU4539 郑厂长系列故事——排兵布阵【状压DP】

2017-08-14 15:51 169 查看
HDU4539链接 

       题意:  一天,郑厂长带着他的军队来到了一个n*m的平原准备布阵。

  根据以往的战斗经验,每个士兵可以攻击到并且只能攻击到与之曼哈顿距离为2的位置以及士兵本身所在的位置。当然,一个士兵不能站在另外一个士兵所能攻击到的位置,同时因为地形的原因平原上也不是每一个位置都可以安排士兵。

  现在,已知n,m 以及平原阵地的具体地形,请你帮助郑厂长计算该阵地,最多能安排多少个士兵。


       输入包含多组测试数据;

       每组数据的第一行包含2个整数n和m (n <= 100, m <= 10 ),之间用空格隔开;

       接下来的n行,每行m个数,表示n*m的矩形阵地,其中1表示该位置可以安排士兵,0表示该地形不允许安排士兵。


     分析:经典状压DP,把每一行安排士兵的状态压缩(利用二进制),然后状态转移方程也比较好写。(如果第一次做这个类型建议先做POJ1185)

   代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
typedef long long LL;
const int N=1<<15;
int n2,n,m;
int dp[105][188][188],w[353],num[353],a[111],b[15];
int dfs(int cnt,int x) //利用DFS深搜放士兵的位置,并记录
{
for(int i=x;i<=m;i++)
{
if(cnt==1||(!b[i]&&!b[i-2]))
{
b[i]=1;
for(int j=1;j<=m;j++)
{
if(b[j])
{w[n2]|=(1<<(j-1));
//cout<<j-1<<" ";
}
}
// cout<<endl;
num[n2]=cnt;
n2++;
dfs(cnt+1,i+1);
b[i]=0;
}
}
}
int main()
{
int x;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(w,0,sizeof(w));
n2=1;
memset(b,0,sizeof(b));
dfs(1,1);
//cout<<n2<<endl;
for(int i=1;i<=n;i++)
{
a[i]=0;
for(int j=0;j<m;j++)
{
scanf("%d",&x);
if(x)
a[i]|=(1<<j);
}
}
memset(dp,-1,sizeof(dp));
for(int i=0;i<n2;i++)
{
if((a[1]|w[i])==a[1])
dp[1][0][i]=num[i];
}
for(int i=1;i<n;i++)
{
for(int j=0;j<n2;j++)
{
for(int k=0;k<n2;k++)
{
if(dp[i][j][k]==-1)continue;
for(int l=0;l<n2;l++)
{
if((a[i+1]|w[l])!=a[i+1])continue;
if(w[j]&w[l]||(w[k]>>1)&w[l]||(w[k]<<1)&w[l])continue;
dp[i+1][k][l]=max(dp[i+1][k][l],dp[i][j][k]+num[l]);

}
}
}
}
int ans=0;
for(int i=0;i<n2;i++)
{
for(int j=0;j<n2;j++)
{
ans=max(dp
[i][j],ans);
}
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: