题意:
给你一个n*n的方格,每个方格一个数字,现在让你取其中的一些数字让数字和最大,
限制条件:如果取了一个数字,那么这个数字周围的八个数字就不能再取
题解:
方格最大15*15,每层2^15种情况,但是其中有很多种非法情况。
复杂度约为 2e7,所以直接暴力可过。
逐层枚举。
另外,每层数量相同,所以枚举种类也是相同的,所以我们枚举一遍即可。
然后把某种状态能到达的状态以邻接表的形式存起来,那么递推的时候只用跑该种状态能到的地方即可,
节约大概10倍时间。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000;
const int maxs=1<<15+10;
char s[maxn];
int num[20][20];
int cnt,len,ed,tt;
int dp[maxs],now[maxs],last[maxs];
int ans[maxs],test[maxs];
void dfs(int r,int pos,int stat,int sum){
if(pos>=ed) {now[++cnt]=stat; ans[cnt]=sum; return;}
dfs(r,pos+1,stat,sum);
dfs(r,pos+2,stat|(1<<pos),sum+num[r][pos+1]);
}
void DP(){
for(int k=1;k<=ed;++k){
cnt=0;
dfs(k,0,0,0);
for(int i=1;i<=cnt;++i) dp[i]=0;
for(int i=1;i<=cnt;++i){
for(int j=1;j<=tt;++j){
if(now[i]&last[j]) continue;
if(now[i]&(last[j]>>1)) continue;
if(now[i]&(last[j]<<1)) continue;
dp[i]=max(dp[i],test[j]+ans[i]);
//printf("dp[%d]=%d ",now[i],dp[i]);
}//puts("");
}
for(int i=1;i<=cnt;++i) test[i]=dp[i];
for(int i=1;i<=cnt;++i) last[i]=now[i];
tt=cnt;
}
}
int main(){
while(gets(s)){
cnt=0;
ed=strlen(s);
for(int len=0;len<ed;len+=3)
num[1][++cnt]=(s[len]-'0')*10+s[len+1]-'0';
ed=cnt;
for(int i=2;i<=ed;++i){
gets(s);cnt=0;
for(int j=1;j<=ed;++j){
num[i][j]=(s[cnt]-'0')*10+s[cnt+1]-'0';
cnt+=3;
}
}
getchar();
test[1]=last[1]=0;
tt=1;
DP();
int sum=0;
for(int i=1;i<=tt;++i) sum=max(sum,test[i]);
printf("%d\n",sum);
}
return 0;
}