方格取数(1)(状压dp入门题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1565
在这里插入图片描述
题意:给你N*N的方格中取数,但不能取相邻的数,(上下左右相邻都不行),求可以取的数之和的最大值。

思路:一道状压dp入门题,因为给的n并不大,我们用一个n位二进制数来表示这一行的n个数取与不取的状态,因为一行之间相邻的不能取,所有我们可以把不符合的数全部筛选除去(i&i>>1)=0就是符合要求的数,不然就是不符合要求的数,原因很简单,我们把i右移一位之后再与原来的数&一下,如果有相邻的1存在,那么i右移一位之后就会1的位置就会对齐,那么&之后就肯定不会是0,删一我们可以用这种方法筛选出符合要求的数,行与行之间,也是一样的道理,假设第i行状态为j,第i-1行状态为k,那么如果符合要求,那么i&j=0,最后我们找出最大值的就可以了。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
int dp[25][20000];
int tot[20000];
int a[25][25];
int fin(int i,int x)
{
    int t=1;
    int sum=0;
    while(x)
    {
        if(x&1)
        {
            sum+=a[i][t];
        }
        x/=2;
        t++;
    }
    return sum;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(dp,0,sizeof(dp));

        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        int cut=0;
        for(int i=0; i<(1<<n); i++)
        {
            if((i&(i>>1))==0)
            {
                tot[++cut]=i;
            }
        }
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=cut; j++)
            {
                int va=fin(i,tot[j]);
                for(int k=1; k<=cut; k++)
                {
                    if((tot[j]&tot[k])==0)
                        dp[i][j]=max(dp[i][j],dp[i-1][k]+va);
                }
            }
        }
        int ma=0;
        for(int i=1; i<=cut; i++)
        {
            ma=max(ma,dp[n][i]);
        }
        printf("%d\n",ma);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43402296/article/details/104969860