小学数位DP之后又去学习状态压缩,这题对于一个入门者还是有点难度的
题意:给你一个n*m的矩阵,叫你求有最多几个炮兵满足不存在任意两炮兵的曼哈顿距离为2
这题自己想了两天没想出来,然后看了解题,有自己的递推来写超时,很无奈,然后还是模仿人家的代码写的
用dp[i][j][k] 表示第i行的状态为k,第i-1行的状态为j,然后转太转移方程是dp[i][j][k] = max(dp[i][j][k],dp[]i-1[k][r]+c[r])
c数组记录的是每个状态中1的个数,cnt数组记录的是每个状态
下面是代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
#include<time.h>
#include<math.h>
#define inf 0x7fffffff
#define eps 1e-9
#define pi acos(-1.0)
#define P system("pause")
using namespace std;
int n,m,tot;
int dp[105][175][175];
int cnt[175],c[175];
int p[105];
void init()
{
int M = 1<<m;
int i,j;
tot = 0;
int flag = 0;
memset(cnt,0,sizeof(cnt));
memset(c,0,sizeof(c));
for(i = 0; i < M; i++)
{
int flag = 1;
for(j = 0; j < m-2; j++)
if( i&(1<<j) && i&(1<<(j+2)) )
{ flag = 0; break;}
if(!flag)continue;
cnt[tot] = i;
for(j = 0; j < m; j++)
if(i&(1<<j))
c[tot]++;
tot++;
}
}
int fun(int i,int j,int k){
if(i > n-2) return 0;
int &ans = dp[i][j][k];
if(ans != -1) return ans;
ans = 0;
for(int r = 0; r < tot; r++)
{
if(p[i+1]&cnt[r]) continue;
if(cnt[r]&cnt[j]) continue;
if((cnt[r]>>1)&cnt[k]) continue;
if((cnt[r]<<1)&cnt[k])continue;
ans = max(ans,fun(i+1,k,r) + c[r]);
// cout<<c[r]<<endl;
}
return ans;
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int i,j;
int g;
while(scanf("%d%d",&n,&m) != EOF)
{
init();
memset(p,0,sizeof(p));
for(i = 0; i < n; i++)
for(j = 0; j < m; j++){
scanf("%d",&g);
p[i] = p[i]*2 + 1 - g;
}
// for(i = 0; i < n; i++)
// cout<<c[i]<<endl;
int ans = 0;
memset(dp,-1,sizeof(dp));
/*for(i = 0; i < tot; i++)
for(j = 0; j < tot; j++){
if(p[0]&cnt[i])continue;
dp[0][j][i] = c[i];
if(c[i] > ans) ans = c[i];
}*/
// cout<<ans<<endl;
/*
for(i = 0; i < n-1; i++)//dp[i][j][k]我这里有递推写为什么会超时,求解释
for(j = 0; j < tot; j++)
for(int k = 0; k < tot; k++)
{
for(int r = 0; r < tot; r++)
{
if(cnt[r]&p[i+1]) continue;
if(cnt[r]&cnt[j]) continue;
if((cnt[r]<<1)&cnt[k]) continue;
if((cnt[r]>>1)&cnt[k]) continue;
dp[i+1][k][r] = max(dp[i+1][k][r], dp[i][j][k] + c[r]);
if(dp[i+1][k][r] > ans) ans = dp[i+1][k][r];
}
}
printf("%d\n",ans);*/
for(i = 0; i < tot; i++){
if(p[0]&cnt[i]) continue;
ans = max(ans,fun(0,0,i)+c[i]);
}
printf("%d\n",ans);
}
// P;
return 0;
}