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

来源:互联网 发布:战锤40k 裁缝店 淘宝 编辑:程序博客网 时间:2024/04/30 22:30

思路 : 

这道题最基本的做法就是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 <iostream>#include <cstdio>#include <vector> #include <memory.h> using namespace std;#define MAXN 14typedef vector<int> 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;} 


2 0
原创粉丝点击