hdu4539(状态压缩)

小学数位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;    
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值