ZOJ3471 Most Powerful,状态压缩DP

这题一开始没有什么想法,后来只能上网看别人的解题报告,看到了状态压缩DP这种做法,好神奇。。。

对于有n个原子,在任何一个状态下,每个原子只有两种状态,要么就是已经被消灭,要么就是还余下来。我们用0表示某个原子还存在,用1表示某个原子被消灭了,这样我们就可以用0到2^n-1个数字来表示任何一种状态了。

对于每一个状态i,我们可以从中挑选两个还存在的原子j和k来进行碰撞,看看碰撞后的能量有没有比原来的多。。。这个很纠结的说明白,我们看看状态转移方程吧

dp[i | (1<<k)] = max(dp[i|(1<<k)],dp[i]+map[j][k]);
i表示第种状态,k表示碰撞后消失的原子,j表示碰撞后还存在的原子。等式左边的dp[i|1<<k]表示碰撞过后的状态的能量,等式右边的dp[i|1<<k]表示原来的能量,因为经过碰撞,k会消失,所以要用i|1<<k来表示。右边的dp[i]+map[j][k]表示在状态i中,经过j和k碰撞,余下j,变成i|1<<k状态后的新的能量。

i经过0到2^n-1次循环,每次循环都循环挑出任意两个还存在的原子碰撞后,最后的能量都储存到dp数组中。最后对dp检索出最大值,就是结果了。


/*******************************************************************************
 # Author : Neo Fung
 # Email : [email protected]
 # Last modified: 2011-10-17 08:54
 # Filename: ZOJ3471 Most Powerful.cpp
 # Description : 
 ******************************************************************************/
// #include "stdafx.h"
// #define DEBUG

#include <fstream>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>
#include <memory.h>
#include <limits.h>

using namespace std;

int map[15][15];
int dp[1<<11];

int main(void)
{
#ifdef DEBUG  
	freopen("data.txt","r",stdin);  
#endif  

	int n;
	while(scanf("%d",&n)&&n)
	{
		int maxint=1<<n;
		for(int i=0;i<n;++i)
			for(int j=0;j<n;++j)
				scanf("%d",&map[i][j]);
		memset(dp,0,sizeof(dp));

		for(int i=0;i<maxint;++i)		//状态从0到2^n-1种
			for(int j=0;j<n;++j)
			{
				if(i & (1<<j)) continue;	//如果在状态i中第j个原子已消失,不计算
				for(int k=0;k<n;++k)
				{
					if(i & (1<<k)) continue;		//如果在状态i中第k个原子已消失,不计算
					if(j==k) continue;			//如果碰撞的两个原子相同,不计算
					dp[i | (1<<k)] = max(dp[i|(1<<k)],dp[i]+map[j][k]);	//状态转移方程
				}
			}
		int ans=0;
		for(int i=0;i<maxint;++i)
			if(dp[i]>ans)
				ans=dp[i];
		printf("%d\n",ans);
	}

	return 0;
}



你可能感兴趣的:(email)