蓝桥杯算法提高 -- 金陵十三钗

思路 : 

这道题最基本的做法就是DFS直接暴力破解, 这样的复杂度毫无疑问的O( n! ), 是不能完全AC的. 那么, 看到这道题问的是最优解, 那么想必跟动态规划能扯上关系了, 但是咋一看, 转移方程可不太好写, 一开始的时候我还写了个错的转移式, 妄想能在O(n^2)内求解...*_*...

言归正传, 使用动态规划的话, 要注意的是 : 在为第 i 个妓女匹配时, 需要在前 i-1 个妓女的所有匹配情况中作综合规划, 那么, 如何记录前 i-1 个妓女的匹配方式便成了首要问题. 因为可选学生的人数n不多于13, 所以可以利用二进制的特性做压缩记录:

比如: 

00000000 表示1个人都没选

00010000 表示选择了第5个学生妹( 从右开始数 )

00010010 表示选择了第5和第2个学生妹( 从右开始数 )


所以, Dp[ i ][ status ]表示前 i 个妓女以status方式选学生妹时的最优相似度, 其中, status二进制中1的数量必然为 i .

树状数组中介绍过用" lowBit( x ) = x & (-x) "的方式来巧妙地提取出x的二进制中最低位的1 .

相似地, " x & ~lowBit(x)"的方式可以巧妙地去除x的二进制中最低位的1

于是, 对于status, 我们可以交替采用上述方法来遍历其中所有的1, 或依次地单独剔除status中的每个1

那么:

Dp[ i ][ status ] = max( Dp[ i-1 ][ 单独剔除1的status ] + Like[ i -1 ][ 提取出来的那个1表示第几个学生妹 ] );

比如(以下status以二进制表示) :

Dp[ 3 ][  0111 ] =Max { 

Dp[2][ 0110 ] + Like[ 2][ 0] ,

Dp[2][ 0101 ] + Like[ 2][ 1],

Dp[2][ 0011 ] + Like[ 2][ 2],

}

单说的确麻烦, 直接上代码:

#include 
#include 
#include  
#include  
using namespace std;

#define MAXN 14
typedef vector Vector;

int Like[MAXN][MAXN]={0};
int dp[2][1<>=1);
	return cnt;
}
// 获取最低位的1 
// 复杂度O( logN ) 
inline int lowBit( int n ){ return n&(-n); }

// 获取最低位的0 的下标 
// 复杂度O( logN ) 
int lowBitPos( int n ){
	int cnt = 0;
	while( n & 1 ){
		++cnt;
		n >>= 1;
	}
	return cnt;
}
int main(int argc, char** argv) {
	scanf("%d",&N);
	// 集合V[i]表示 : 二进制下1的数量为i的数的集合 
	// 复杂度O( 2^N ) * O( logN )
	for( int i = 0, End=(1<


你可能感兴趣的:(C++)