格子取数(HDU-1565)(状圧DP)


n*nの格子の碁盤をあげて、各格子の中に非負の数があります.任意の2つの数が存在する格子に共通のエッジがないように、いくつかの数を取り出します.つまり、取得した数が存在する2つの格子が隣接することができず、取得した数の和が最大になります.
Input
複数のテストインスタンスを含み、各テストインスタンスは1つの整数nとn*nの非負の数(n<=20)を含む.
Output
各テストインスタンスについて、取得可能な最大和を出力します.
Sample Input
3
75 15 21 
75 15 28 
34 70 5 

Sample Output
188

中国語の問題なので、問題の意味はもう説明しません.
考え方:この問題は、DPを押す問題です.まず、列ごとにバイナリ状態にすることができます.それから、状態が合法かどうかを判断するだけでいいです.
ACコード:
#include 
typedef long long ll;
const int maxx=10010;
const int inf=0x3f3f3f3f;
using namespace std;
int a[19][1<<17];
int f[19][1<<17];
int b[maxx];
int calc(int i,int x)
{
    int cnt=1,ans=0;
    while(x)
    {
        if(x&1)
            ans+=a[i][cnt];
        x/=2;
        cnt++;
    }
    return ans;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        int cnt=0,ans=0;
        for(int i=0; i >1))==0)
                b[++cnt]=i;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
                scanf("%d",&a[i][j]);
        memset(f,0,sizeof(f));
        for(int i=1; i<=n; i++)
        {
            for(int k=1; k<=cnt; k++)
            {
                int val=calc(i,b[k]);
                for(int j=1; j<=cnt; j++)
                {
                    if((b[j]&b[k])==0)
                    {
                        f[i][k]=max(f[i][k],f[i-1][j]+val);
                    }
                }
            }
        }
        for(int j=1; j<=cnt; j++)
            ans=max(ans,f[n][j]);
        printf("%d
",ans); } return 0; }