方格取数 HDU - 1565 (状压dp)

Posted alexlins

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了方格取数 HDU - 1565 (状压dp)相关的知识,希望对你有一定的参考价值。

    给你一个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

思路:状压dp,建立dp【i】【j】二维数组,表示第i行状态为j的最大取值
   推出其状态转移方程:dp【i】【j】=max(dp【i】【j】,dp【i-1】【k】+sum),其中sum表示j状态下的取值。

   注意开的数组大小。

代码:

#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
",a);
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 = 1e8;
const int Maxn = 21;
const double pi = acos(-1.0);
const double eps = 1e-8;

int n, 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 k) { //判断x与第k行的实际状态的逆是否有 重合‘
//    if (x & cur[k]) return false;//若有重合,则x不符合要求
//    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() {
    while (~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 (!(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;
}

 

以上是关于方格取数 HDU - 1565 (状压dp)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 1565 方格取数

HDU 1565 - 方格取数 - [状压DP][网络流 - 最大点权独立集和最小点权覆盖集]

hdu 1565 方格取数(状态压缩dp)

HDU 2167 状压dp方格取数

hdu 2167 方格取数 状压dp(经典)

HDU 1565 1569 方格取数(最大点权独立集)