方格取数(1)
Problem Description
给你一个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
解题思路:
给合法状态打标记,然后枚举依次枚举每层的状态就可以了。
(垃圾题目毁我青春,RE两小时,n居然可以等于0)
AC代码:
#include <bits/stdc++.h>
#include <iostream>
#include <stdlib.h>
#include <cstdio>
#include <cstring>
#include <utility>
#include <string>
#define INF 0xfffffff
#define int long long
using namespace std;
const int mod = 1e9+7;
const int N = 20;
int a[N][N];
int mark[1<<17];
int cnt_=0;
int dp[N][1<<17];
int get_sum(int lev,int sta,int n)
{
int sum = 0;
for(int i = 0; i < n ; i ++)
{
if(((1<<i)&sta) != 0)
sum += a[lev][i];
}
return sum;
}
signed main()
{
int n;
for(int i = 0 ; i < (1<<17) ; i ++)
{
if((i&(i<<1)) == 0)
mark[cnt_++] = i;
}
while(cin>>n)
{
if(n == 0){
cout<<0<<endl;
continue;
}
for(int i = 0 ; i < n ; i ++)
for(int j = 0 ; j < n ; j ++)
cin>>a[i][j];
memset(dp,0,sizeof(dp));
for(int i = 0; mark[i] < (1<<n) ; i++)
dp[0][mark[i]] = get_sum(0,mark[i],n);
for(int i = 1; i < n ; i ++)
{
for(int j = 0 ; mark[j] < (1<<n) ; j ++)
{
int val = get_sum(i,mark[j],n);
for(int k = 0 ; mark[k] < (1<<n) ; k ++)
{
if((mark[k]&mark[j]) == 0)
dp[i][mark[j]] = max(dp[i][mark[j]],dp[i-1][mark[k]]+val);
}
}
}
int ans = 0;
for(int j = 0 ; mark[j] < (1<<n) ; j ++)
ans = max(ans,dp[n-1][mark[j]]);
cout<<ans<<endl;
}
return 0;
}