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

思路 :

这道题最基本的做法就是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

扫描二维码关注公众号,回复: 5619837 查看本文章

那么:

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 <memory.h>
using namespace std;

#define MAXN 14
typedef vector Vector;

int Like[MAXN][MAXN]={0};
int dp[2][1<<MAXN];
int N;
Vector V[MAXN];

// 计算n的二进制表示中1的数量
// 复杂度O( logN )
int CountOfOne( int n ){
int cnt = 0;
do{
cnt += (n&1);
}while(n>>=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<<N); i < End; ++i)
V[ CountOfOne(i) ].push_back( i );

for( int i=0,j; i < N; ++i)
	for( j=0; j < N; ++j )
		scanf("%d",&Like[i][j]);
		
memset(dp,0,sizeof(dp));		
int E=0;
// 复杂度O( 2^N ) * O( logN )
for( int i = 1; i <= N; ++i ){
	E = 1-E;
	for( Vector::iterator it=V[i].begin(), End=V[i].end(); it != End; ++it ){
		for(int status = *it, temp=*it, times=0, lb; times < i; ++times){
			lb = ~lowBit(temp);
			dp[E][status] = max(dp[E][status], dp[1-E][status&lb]+Like[i-1][lowBitPos(lb)]);
			temp &= lb;
		}
	}
}
printf("%d",dp[E][(1<<N)-1]);
return 0;

}

作者:Lonverce
来源:CSDN
原文:https://blog.csdn.net/lonverce/article/details/50164587
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/a1_s2_c3_/article/details/88070447
今日推荐