Maximum Sum Gym - 101853E (状压dp)

You are given a grid consisting of n rows each of which is dived into n columns. The rows are numbered from 1 to n from top to bottom, and the columns are numbered from 1 to n from left to right. Each cell is identified by a pair (x, y), which means that the cell is located in the row x and column y. All cells in the grid contain positive integers.

Your task is to choose a subset of the grid's cells, such that their summation is as maximal as possible, and there are no two adjacent cells in that subset. Two cells are considered adjacent if they are horizontal, vertical, or diagonal neighbors.

Input

The first line contains an integer T (1 ≤ T ≤ 100), in which T is the number of test cases.

The first line contains an integer n (1 ≤ n ≤ 16), in which n is the number of rows and columns in the grid.

Then n lines follow, each line contains n integers, giving the grid. All values in the grid are between 1 and 1000 (inclusive).

Output

For each test case, print a single line containing the maximum sum of a subset of the grid's cells. The chosen subset must not contain any adjacent cells.

Example

Input
2
2
4 7
2 9
3
1 2 3
4 5 6
7 8 9
Output
9
20

这道题之前在训练赛中没写出来,现在补上。

题意:跟【hdu1656 方格取数】这道题差不多,在n*n方格中取数,所取的数所在的2个格子不能相邻(斜着也不能相邻),并且取出的数的和最大。

扫描二维码关注公众号,回复: 10783972 查看本文章

代码:

#include <iostream>
#include <algorithm>
#include <string.h>
#include <cstdio>
#include <string>
#include <cmath>
#include <vector>
#include <stack>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
//#include <unordered_map>
#define Fbo friend bool operator < (node a, node b)
#define mem(a, b) memset(a, b, sizeof(a))
#define FOR(a, b, c) for (int a = b; a <= c; a++)
#define RFOR(a, b, c) for (int a = b; a >= c; a--)
#define off ios::sync_with_stdio(0)
#define sc(a) scanf("%d",&a)
#define pr(a) printf("%d\n",a);
#define SC(n,m) scanf("%d%d",&n,&m)
bool check1(int a) { return (a & (a - 1)) == 0 ? true : false; }

using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
const int INF = 0x3f3f3f3f;//1e10
const int mod = 1e9+7;
const int Maxn = 20;
const double pi = acos(-1.0);
const double eps = 1e-8;

int n, t, top; //top表示每行最多的状态数
int state[1<<16];//所有可能方案
int dp[Maxn][1<<16];//对于前i行数据,每行有前j种可能时候的解
int sum[Maxn][1<<16];
int a[Maxn][Maxn];
//int cur[Maxn];//表示第i行整行的时候

inline bool ok(int x) { //判断x的二进制数是否有相邻的1
    if ((x & (x >> 1))) return false; //x有相邻的1,不合法
    return true; //合法
}

void init() { //初始化合法的方案
    top = 0;
    int total = 1 << n; //遍历状态的上界
    for (int i = 0; i < total; i++) {
        if (ok(i)) state[top++] = i;
    }
}

inline bool fit(int x, int y) { //判断x与第k行的实际状态的逆是否有 重合'
    if (x & y) return false;//若有重合,则x不符合要求
    if (x & (y >> 1) || (x >> 1) & y) return false; //这里是判断斜着是否相邻
    return true;
}

int cal(int k, int sta) {//求第i行状态为state时的取值总和
    int res = 0;
    FOR(i, 0, n-1) {
        if ((sta >> i) & 1) {
            res += a[k][n - i - 1];
        }
    }
    return res;
}

int main() {
    sc(t);
    while (t--) {
        sc(n);
        FOR(i, 0, n-1)FOR(j, 0, n-1)sc(a[i][j]);
        mem(sum, 0);
        mem(dp, 0);
        init();
         /*数据处理,求出所有取值和*/
        FOR(i, 0, n-1) {
            for (int j = 0; j < top; j++) {
                sum[i][j] += cal(i, state[j]);
                //cout << sum[i][j] << " ";
            }
        }
        //cout << endl;
        /*
       状态转移过程中,dp[i][k] =Sigma dp[i-1][j] (j为符合条件的所有状态) */
        for (int i = 0; i < top; i++) dp[0][i] = sum[0][i];// cout << sum[0][i] << "—— ";
        //cout << endl;
        for (int i = 1; i < n; i++) { //行数
            for (int k = 0; k < top; k++) { //本行状态
                for (int j = 0; j < top; j++) { //上一行状态
                    if ((fit(state[k],state[j])))//判断是否与第i行冲突
                        dp[i][k] = max(dp[i][k], dp[i - 1][j] + sum[i][k]);
                }
            }
        }
        /*寻找最大和*/
        int res = dp[n-1][0];
        for (int i = 0; i < top; i++) {
            res = max(dp[n-1][i], res);
        }
        pr(res);
    }
    return 0;
}

 

猜你喜欢

转载自www.cnblogs.com/AlexLINS/p/12697161.html