原题地址:https://codeforces.com/gym/101853/problem/E
题意:给出一个n*n的矩阵,矩阵中每一个格子都有一个权值,选择一个格子就能拿到当前的权值,但是同时就不能选择这个格子四周的八个格子.现在询问你获得的最大权值是多少.
思路:状压dp.预处理出所有每一行合法的状态,然后dp处理就行了
#include <bits/stdc++.h>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 1e5 + 5;
const int mod = 998244353;
int t, n;
int a[20][20];
int state[maxn], top;
int fit(int x) {
if (x & (x << 1)) return 1;
return 0;
}
int fit(int x, int y) {
if (x & y) return 0;
if (x & (y << 1)) return 0;
if (x & (y >> 1)) return 0;
return 1;
}
int dp[20][maxn];//dp[i][j]表示第i行状态为j时的总数
int main() {
scanf("%d", &t);
while (t--) {
top = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
scanf("%d", &a[i][j]);
}
}
for (int i = 0; i < (1 << n); i++) {
if (fit(i)) continue;
state[top++] = i;
}
CLR(dp, 0);
for (int i = 0; i < top; i++) {
for (int j = 0; j < n; j++) {
if ((state[i] >> j) & 1) dp[1][i] += a[1][n - j];//当前行状态为state[j]时的价值
}
}
for (int i = 2; i <= n; i++) { //第i行
for (int j = 0; j < top; j++) { //第i行状态
for (int k = 0; k < top; k++) { //第i-1行状态
if (!fit(state[j], state[k])) continue;
int sum = 0;
for (int r = 0; r < n; r++) {
if ((state[j] >> r) & 1) sum += a[i][n - r];
}
dp[i][j] = max(dp[i][j], dp[i - 1][k] + sum);
}
}
}
int MAX = 0;
for (int i = 0; i < top; i++) MAX = max(MAX, dp[n][i]);
printf("%d\n", MAX);
}
return 0;
}