您的位置:首页 > 其它

HDU 4539 郑厂长系列故事——排兵布阵 (状态压缩DP)

2014-08-13 16:23 387 查看
中文题,题意不再累赘。

思路:对于第 i 行的放士兵,影响它的只有第 i-1 行和 i-2 行,所以暴力枚举符合这三行的状态

state[i],state[j],state[k]. 接下来就是二进制的巧妙应用了。

具体题解看代码注释!!!

#include<cstdio>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<map>
#include<cmath>
#include<iostream>
#include <queue>
#include <stack>
#include<algorithm>
#include<set>
using namespace std;
#define INF 1e8
#define inf -0x3f3f3f3f
#define eps 1e-8
#define LL long long
#define N 100001
#define mol 100000000

int lp(int a,int b)
{
return a&b;
}
int dp[105][200][200];//dp[i][j][k],表示第 i 行是 state[j]状态i-1行是state[k]状态的最大值
int state[200];//符合规定的状态
int base[200];//给定矩阵的初始状态
int sum[200];//sum[i]:状态satet[i]的士兵数
int n,m,g;
int main()
{
while(~scanf("%d%d",&n,&m))
{
memset(base,0,sizeof(base));
memset(dp,0,sizeof(dp));
memset(state,0,sizeof(state));
memset(sum,0,sizeof(sum));
if(n==0||m==0)
{
printf("0\n");
continue;
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
scanf("%d",&g);
if(g==0)
base[i]+=1<<(j);//初始状态二进制表示
}
}
int num=0;
for(int i=0;i<(1<<m);i++)
{
if(lp(i,i<<2)||lp(i,i>>2)) continue;//状态i要满足它不能攻击它的前两个和后两个
int k=i;
while(k)//算出k有多少个1(士兵)
{
sum[num]+=k&1;
k=k>>1;
}
state[num++]=i;
}
for(int i=0;i<num;i++)//初始第0行的状态
{
if(lp(state[i],base[0])) continue;
dp[0][i][0]=sum[i];
}
for(int i=0;i<num;i++)//在满足第0行的状态下寻找第1行的状态
{
if(lp(state[i],base[1])) continue;
for(int j=0;j<num;j++)
{
if(lp(state[j],base[0])) continue;
if(lp(state[j]<<1,state[i])||lp(state[j]>>1,state[i])) continue;
dp[1][i][j]=max(dp[1][i][j],dp[0][j][0]+sum[i]);
}
}
for(int i=0;i<num;i++)//在满足第0,1行的状态下寻找第2行的状态
{
if(lp(state[i],base[2])) continue;
for(int j=0;j<num;j++)
{
if(lp(state[j],base[1])) continue;
for(int k=0;k<num;k++)
{
if(lp(state[k],base[0])) continue;
if(lp(state[i]<<1,state[j])||lp(state[i]>>1,state[j])) continue;
if(lp(state[j]<<1,state[k])||lp(state[j]>>1,state[k])) continue;
if(lp(state[i],state[k])) continue;
dp[2][i][j]=max(dp[2][i][j],dp[1][j][k]+sum[i]);
}
}
}
for(int r=3;r<n;r++)//从第3行开始
{
for(int i=0;i<num;i++)//暴力枚举三行的状态state[i],state[j],state[k]
{
if(lp(base[r],state[i])) continue;
for(int j=0;j<num;j++)
{
if(lp(base[r-1],state[j])) continue;
if(lp(state[i]<<1,state[j])||lp(state[i]>>1,state[j])) continue;
for(int k=0;k<num;k++)
{
if(lp(base[r-2],state[k])) continue;
if(lp(state[j]<<1,state[k])||lp(state[j]>>1,state[k])) continue;
if(lp(state[i],state[k])) continue;
dp[r][i][j]=max(dp[r-1][j][k]+sum[i],dp[r][i][j]);
}
}
}
}
int ans=0;
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
ans=max(ans,dp[n-1][i][j]);
}
printf("%d\n",ans);
}
return 0;
}
/*
6 6
1 0 0 0 0 1
0 0 0 0 0 0
0 0 1 1 0 0
0 0 1 1 0 0
0 0 1 1 0 0
1 0 1 1 0 1

3 3
1 1 1
1 1 1
1 1 1

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

6 6
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1

0 6

1 6
1 1 1 1 1 1

2 6
1 1 1 1 1 1
1 1 1 1 1 1

Answer:
6
3
2
12
0
4
4
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: