链接
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!