HDU-1565-方格取数(1)(状压DP)

方格取数(1)

Problem Description

给你一个n*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。

Input

包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20)

Output

对于每个测试实例,输出可能取得的最大的和

Sample Input

3
75 15 21 
75 15 28 
34 70 5 
 

Sample Output

188
 

解题思路:

给合法状态打标记,然后枚举依次枚举每层的状态就可以了。
(垃圾题目毁我青春,RE两小时,n居然可以等于0)

AC代码:

#include <bits/stdc++.h>
#include <iostream>
#include <stdlib.h>
#include <cstdio>
#include <cstring>
#include <utility>
#include <string>
#define INF 0xfffffff
#define int long long

using namespace std;
const int mod = 1e9+7;
const int N = 20;
int a[N][N];
int mark[1<<17];
int cnt_=0;
int dp[N][1<<17];

int get_sum(int lev,int sta,int n)
{
    int sum = 0;
    for(int i = 0; i < n ; i ++)
    {
        if(((1<<i)&sta) != 0)
            sum += a[lev][i];
    }
    return sum;
}

signed main()
{
    int n;
    for(int i = 0 ; i < (1<<17) ; i ++)
    {
        if((i&(i<<1)) == 0)
            mark[cnt_++] = i;
    }
    while(cin>>n)
    {
        if(n == 0){
                cout<<0<<endl;
            continue;
        }
        for(int i = 0 ; i < n ; i ++)
            for(int j = 0 ;  j < n ; j ++)
                cin>>a[i][j];
        memset(dp,0,sizeof(dp));
        for(int i = 0; mark[i] < (1<<n) ; i++)
            dp[0][mark[i]] = get_sum(0,mark[i],n);
        for(int i = 1; i < n ; i ++)
        {
            for(int j = 0 ;  mark[j] < (1<<n) ; j ++)
            {
                int val = get_sum(i,mark[j],n);
                for(int k = 0 ; mark[k] < (1<<n) ; k ++)
                {
                    if((mark[k]&mark[j]) == 0)
                        dp[i][mark[j]] = max(dp[i][mark[j]],dp[i-1][mark[k]]+val);
                }
            }
        }
        int ans  = 0;
        for(int j = 0 ;  mark[j] < (1<<n) ; j ++)
            ans = max(ans,dp[n-1][mark[j]]);
        cout<<ans<<endl;
    }
    return 0;
}

发布了104 篇原创文章 · 获赞 7 · 访问量 4067

猜你喜欢

转载自blog.csdn.net/qq_43461168/article/details/104144620