hdu 1565 方格取数(1) dp+状态压缩

/*
用0表示没选这个数,用1表示没选
那么n<=20那么每一列的情况就可以用二进制数表示
前一列能到后一列的状态的条件是前面一列的二进制状态和后一列的二进制状态‘与’为0
而对于这些二进制状态所表示的数必须满足没有相邻的1,从而保证每一行满足条件
*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 30
#define maxs 1<<20
#define inf 0x7ffffff
int dp[maxs][maxn];//dp[i][j]第i个满足条件的二进制状态在第j列的最大值
int useful[maxs];//记录满足条件的二进制数
int chess[maxn][maxn];
int n;
int judge(int i)//判断这个数是否满足条件
{
    int t=i;
    int cur;
    int pre=t%2;
    t/=2;
    while(t)
    {
        cur=t%2;
        if(cur&&pre)
        return 0;
        t/=2;
        pre=cur;
    }
    return 1;
}
int  count(int sum,int j)//计算sum这个二进制状态下载第j列的取值
{
    int t=sum;
    int pos=0;
    int ans=0;
    while(t)
    {
        if(t%2)
        ans+=chess[pos][j];
        pos++;
        t/=2;
    }
    return ans;
}
int init()
{
    int k=0;int i;
    int upper=1<<n;
    for(i=0;i<upper;i++)
    if(judge(i))
    {useful[k++]=i;}//存下所有满足条件的二进制状态
    for(i=0;i<k;i++)
    dp[i][0]=count(useful[i],0);
    return k;
}
int main()
{
    int i,j,k;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=0;i<n;i++)
        for(j=0;j<n;j++)
        scanf("%d",&chess[i][j]);
        int upper=init();
        for(j=1;j<n;j++)
        for(i=0;i<upper;i++)
        {
            int temp=-inf;
            for(k=0;k<upper;k++)
            if((useful[k]&useful[i])==0)//前一列能转化为后一个的条件是它们的二进制状态的‘与’为0
            temp=max(temp,dp[k][j-1]);
            dp[i][j]=temp+count(useful[i],j);
        }
        int ans=-inf;
        for(i=0;i<upper;i++)
        ans=max(ans,dp[i][n-1]);
        printf("%d\n",ans);
    }
    return 0;
}






   
  
     

你可能感兴趣的:(hdu 1565 方格取数(1) dp+状态压缩)