题目大意:
一个n*n的格子的棋盘,每个格子里面有一个非负数。从中取出若干个数,使得任意的两个数所在的格子没有公共边,并且取出的数的和最大。
解题思路:
因为两个数之间不能相邻,即每行用状态表示出来,1表示取,0表示不取,所以状态方程为dp[i][j]=max(dp[i][j],dp[i-1][k]+val);(第一维表示行数,第二维表示行的状态)当(sta[j]&sta[k])==0时,我们可以先用打表的方式求得状态表示。
代码:
#include<bits/stdc++.h>
#define pb emplace_back
#define LOCAL
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5+5;
typedef long long ll;
typedef pair<int,int> Pii;
template <typename T>inline void read(T& t){
char c=getchar();t=0;
int f=1;
while(!isdigit(c)){
if(c=='-')f=-1;
c=getchar();
}
while(isdigit(c))t=t*10+c-48,c=getchar();
t=f*t;
}
template <typename T,typename... Args> inline void read(T& t,Args&... args){
read(t);read(args...);
}
int tot=0;
int sta[maxn];
int a[25][25];
int ksm(int i,int sta){
int ans=0,res=1;
while(sta){
if(sta&1){
ans+=a[i][res];
}
res++;
sta>>=1;
}
return ans;
}
int main(){
int n;
while(cin>>n){
tot=0;
for(int i=0;i<(1<<n);i++){
if((i&(i>>1))==0){
sta[tot++]=i;//每增加一列状态,如果都与前面取过得数不相邻,则存入状态
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
read(a[i][j]);
}
}
vector<vector<int>>dp(n+1,vector<int>((1<<n),0));
for(int i=1;i<=n;i++){
for(int j=0;j<tot;j++){
for(int k=0;k<tot;k++){
if(!(sta[j]&sta[k])){
int val=ksm(i,sta[j]);
dp[i][j]=max(dp[i][j],dp[i-1][k]+val);
}
}
}
}
int ans=0;
for(int i=0;i<tot;i++){
ans=max(ans,dp[n][i]);
}
printf("%d\n",ans);
}
return 0;
}