HDOJ/HDU 1565 方格取数(1)
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1565
题目意思就是说给出一个n*n的棋盘,每个位置上有一个非负整数,在上面取不相邻的若干个数,使得和最大。
解法:位运算+dp
因为每行可以取的位置都是一样的,只要两个数不相邻即可。所以可以先对1<<n以内处理,筛除不合法的,优化效率,然后对每行的每一个状态,在上一行合法而且跟本状态不冲突的所有状态中找一个和最大的。本行的本状态的值就是这一行在这个状态下取得的所有数的和+这个最大值。如果是第一行,则上一行的最大值为0;
需要注意的一个地方就是n可能为0,(>_<)我看了discuss才知道这么个变态的情况,如果为0直接输出0即可。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <map>
#include <cstring>
#include <string.h>
#include <fstream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
int d[1<<20], k, n, a[25][25];
__int64 sum[25][1<<20];
void init(int n){
k = 0;
int j;
for (j = 0; j < 1<<n; j++){
if (j&(j<<1) || j&(j>>1))
continue;
d[k++] = j;
}
}
__int64 get_sum(int i, int j)
{
int l = n;
__int64 tot = 0;
while (j > 0){
if (j % 2)
tot += a[i][l];
j /= 2;
l--;
}
return tot;
}
int main(){
int i, j, l;
while (scanf("%d", &n) != EOF){
for (i = 1; i <= n; i++)
for (j = 1; j <= n; j++)
scanf("%I64d", &a[i][j]);
init(n);
for (i = 1; i <= n; i++)
{
for (j = 0; j < k; j++)
{
if (i == 1){
sum[i][j] = get_sum(i, d[j]);
continue;
}
__int64 temp = -1;
for (l = 0; l < k; l++){
if (d[j] & d[l])continue;
temp = max(temp, sum[i-1][l]);
}
sum[i][j] = temp + get_sum(i, d[j]);
}
}
__int64 maxf = -1;
for (i = 1; i <= n; i++)
for (j = 0; j < k; j++)
maxf = max(maxf, sum[i][j]);
printf("%I64d\n", maxf);
}
return 0;
}
浙公网安备 33010602011771号