solve:设dp[ i ] [ j ]为枚举到第i行,状态为 j 的数的最大值,那么,枚举上一行的状态,如果没有直接相邻的边,就转移,最后答案就是所有状态的max。这题会卡空间,可以用滚动数组,也可以计算出行的所有的可行状态,大概是2e4,然后把所有的状态保存下来,这样时间复杂度还是不ok的,因为枚举了两行状态和行,时间复杂度4e8*20 = 8e9,但是样例水呀,就过去了,正解应该是网络流。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 21;
int a[maxn][maxn];
int dp[2][1<<maxn];
int sta[1<<maxn],cnt,n;
int sum(int k,int s)
{
int ans = 0;
for(int i=0;i<n;i++)
if((1<<i&s))ans += a[k][i];
return ans;
}
int main()
{
while(~scanf("%d",&n))
{
cnt = 0;
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)scanf("%d",&a[i][j]);
for(int i=0;i<1<<n;i++)
if((i<<1&i)==0 && (i>>1&i)==0)sta[++cnt] = i;
int ans = 0;
for(int i=1;i<=cnt;i++)
{
dp[0][sta[i]] = sum(0,sta[i]);
ans = max(ans,dp[0][sta[i]]);
}
int cur = 0;
for(int i=1;i<n;i++)
{
cur^=1;
for(int s=1;s<=cnt;s++)
{
dp[cur][sta[s]] = 0;
for(int s0=1;s0<=cnt;s0++)
{
if((sta[s]&sta[s0])!=0)continue;
dp[cur][sta[s]]=max(dp[cur][sta[s]],dp[cur^1][sta[s0]] + sum(i,sta[s]));
ans = max(ans,dp[cur][sta[s]]);
}
}
}
cout<<ans<<'\n';
}
}