HUD 1565方格取数(1)
思路:状压DP,考虑对于每一行把合法状态全部筛选出来,也就是满足(i)&(i>>1)=0的状态放进集合里面,对于每一行可以转移的上一行的状态是i&j=0,转移方程就出来了。
#include<iostream>
#include<vector>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=30,M=20000;
int n;
typedef long long ll;
vector<int>state;
int num[N][N];
ll dp[2][M];
bool check(int x)
{
if(x&(x>>1))return true;
return false;
}
ll max(ll a,ll b)
{
if(a>b)return a;
return b;
}
ll sum(int r,int x)
{
ll res=0;
for(int i=0;i<n;i++)
{
if(x&(1<<i))res+=num[r][n-i];
}
return res;
}
void init()
{
for(int i=0;i<int(1<<20);i++){
if(!check(i))state.push_back(i);
}
return;
}
int main ()
{
//ios::sync_with_stdio(0);
//cin.tie(0);
init();
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&num[i][j]);
int cur=0;
ll mmax=0;
//for(int i=0;i<int(state.size())&&state[i]<(1<<n);i++)dp[0][i]=0;
dp[0][0]=0;
for(int i=1;i<=n;i++)
{
cur^=1;
for(int j=0;(j<int(state.size()))&&(state[j]<(1<<n));j++)
{
dp[cur][j]=0;
if(i!=1){
for(int t=0;(t<int(state.size()))&&(state[t]<(1<<n));t++){
if(state[j]&state[t])continue;
dp[cur][j]=max(dp[cur][j],dp[cur^1][t]);
}}
dp[cur][j]+=sum(i,state[j]);
//mmax=max(mmax,dp[cur][j])
}
}
for(int i=0;(i<int(state.size()))&&(state[i]<(1<<n));i++)mmax=max(mmax,dp[cur][i]);
cout<<mmax<<endl;
}
return 0;
}