方格取数(HDU1565)状压dp入门

链接

Click here to see the original question

题目描述

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

输入

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

输出

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

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
int n, choices[100009], rowsum[100009], totalsum[100009], board[30][30], choicenum;

void dfs(int row, int cur_col, int choice, int sum) {
    //choice用二进制的形式来记录,比如说4*4的棋盘,对于每一行,choice值为1表示0001,即选中第1列;值为10代表1100,即选中第3列和第4列
    if(cur_col > n){//已到超出了最后一列,则把数据记录下来并返回
        choicenum++;//新增一种情况
        choices[choicenum] = choice;//choices记录该行的选择情况
        rowsum[choicenum] = sum;//rowsum记录在该种选择的情况下的和
        return;
    }
    //选择当前位置
    //则下一位至少隔一个数,即列数+2
    dfs(row, cur_col + 2, choice + (1 << (cur_col - 1)), sum + board[row][cur_col]);
    //不选择当前位置
    dfs(row, cur_col + 1, choice, sum);
}

void getAns() {
    int pre_choice[100009], pre_size, maxsum[100009];
    choicenum = 0;
    dfs(1, 1, 0, 0);//遍历第一行
    pre_size = choicenum;
    for(int i = 1; i <= choicenum; i++){
        pre_choice[i] = choices[i];
        totalsum[i] = rowsum[i];
    }
    for(int i = 2; i <= n; i++){
        choicenum = 0;
        dfs(i, 1, 0, 0);//遍历第i行
        memset(maxsum, 0, sizeof(maxsum));
        for(int j = 1; j <= choicenum; j++){
            for(int k = 1; k <= pre_size; k++){
                if(pre_choice[k] & choices[j]) continue;//相与为1,证明有相邻,不符合条件,跳过
                maxsum[j] = max(maxsum[j], totalsum[k] + rowsum[j]);//maxsum[i]:当前行采用第i种选择时和的最大值
            }
        }
        for(int j = 1; j <= choicenum; j++){//将这一行的数据保存到上一行
            pre_choice[j] = choices[j];
            totalsum[j] = maxsum[j];
        }
        pre_size = choicenum;
    }
}

int main() {
    while(cin>>n) {
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                cin>>board[i][j];
            }
        }
        getAns();
        int ans = 0;
        for(int i = 1; i <= choicenum; i++){
            ans = max(ans, totalsum[i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

如果您觉得我的文章对您有帮助的话,可以点个赞,点个关注,也可以扫描下方二维码关注我。我将在这个公众号上更新自己的学习笔记,以及分享一些算法知识

Study and progress together with me!

img

猜你喜欢

转载自blog.csdn.net/qq_45359344/article/details/107644704