输入比赛人员个数 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] )
时间: 2024-10-18 16:16:50