HDU 方格取数(1) (状压DP)

link 

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';
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_44499508/article/details/105466622