输入比赛人员个数 N 和你希望赢的人的编号 M,
然后输入 N * N 的输赢表,第 i 行 第 j 列为 1,代表 i 能赢 j。
求 M 最后能赢,且总比赛树的最小高度时,一共有多少种可能。
比如输入:
7 2
0 1 0 0 0 1 0
0 0 1 0 1 1 1
1 0 0 1 1 0 0
1 1 0 0 0 1 0
1 0 0 1 0 0 1
0 0 1 0 1 0 0
1 0 1 1 0 1 0
则输出:
139
#include <iostream>
#include <vector>
#include <cstring>
#include <cmath>
using namespace std;
vector< int > wins_table[16];
int DP[16][20][1 << 16];
int one_in_bits_[1 << 16];
int dfs_search( int root, int height, int set_bits ){
if( one_in_bits_[set_bits] == 1 )
return 1;
if( ( 1 << height ) < one_in_bits_[set_bits] )
return 0;
if( DP[root][height][set_bits] != -1 )
return DP[root][height][set_bits];
else
DP[root][height][set_bits] = 0;
for( int set1 = set_bits & ( set_bits - 1 ); set1; set1 = set_bits & ( set1 - 1 ) ){
if( ( set1 >> root ) & 1 ){
int set2 = set1 ^ set_bits;
for( int i = 0; i < wins_table[root].size(); ++i ){
int other = wins_table[root][i];
if( ( set2 >> other ) & 1 ){
DP[root][height][set_bits] += dfs_search( root, height - 1, set1 ) *
dfs_search( other, height - 1, set2 );
}
}
}
}
return DP[root][height][set_bits];
}
int main(){
for( int i = 0; i < ( 1 << 16 ) - 1; ++i )
one_in_bits_[i] = one_in_bits_[i >> 1] + ( i & 1 );
int players, winner;
while( cin >> players >> winner ){
memset( DP, -1, sizeof( DP ) );
for( int i = 0; i < players; ++i ){
wins_table[i].clear();
for( int j = 0; j < players; ++j ){
int win;
cin >> win;
if( win )
wins_table[i].push_back( j );
}
}
int height = ceil( log( players ) / log( 2 ) );
int ans = dfs_search( winner - 1, height, ( 1 << players ) - 1 );
cout << ans << endl;
}
return 0;
}
DP[root][height][set] 代表 以 root 为根,比赛树高度为 height 时,已经比赛过人员集合为 set 时的可能性
则 DP[root][height][set] = ∑ ( DP[root][height - 1][set1] * DP[other][height - 1][set - set1] )
SGU-448 Controlled Tournament ( 状态DP )
原文:http://blog.csdn.net/pandora_madara/article/details/42749673