方格取数 HDU - 1565 (状压dp)
Posted alexlins
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了方格取数 HDU - 1565 (状压dp)相关的知识,希望对你有一定的参考价值。
给你一个n*n的格子的棋盘,每个格子里面有一个非负数。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大。
从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的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)的主要内容,如果未能解决你的问题,请参考以下文章