Problem Statement | |||||||||||||
N people (where N is a power of 2) are taking part in a single-elimination tournament in cheese rolling. The diagram below illustrates the structure of the tournament bracket.
The people entering the tournament are numbered from 0 to N-1. For each potential cheese rolling match you know who would win the match. You are given this information encoded as a vector <string> wins with N elements, each containing N characters. For each valid i and j, wins[i][j] is 'Y' if person i beats person j. Otherwise, wins[i][j] is 'N'. The relation is not necessarily transitive: it may be the case that person i beats person j, person j beats person k, and person k beats person i. There are N! (N factorial) ways to assign the people to positions in the bracket. Different assignments may produce a different winner of the tournament. Return a vector<long long> with N elements. For each valid i, element i of the return value should be the exact number of assignments for which person i wins the tournament. | |||||||||||||
Definition | |||||||||||||
| |||||||||||||
Limits | |||||||||||||
| |||||||||||||
Constraints | |||||||||||||
- | N will be between 2 and 16, inclusive. | ||||||||||||
- | N will be a power of 2. | ||||||||||||
- | wins will contain exactly N elements. | ||||||||||||
- | Each element of wins will have a length of exactly N. | ||||||||||||
- | Each element of wins will be composed of the characters 'Y' and 'N'. | ||||||||||||
- | For each i from 0 to N-1, wins[i][i] = 'N'. | ||||||||||||
- | For all distinct integers i and j from 0 to N-1, exactly one of wins[i][j] and wins[j][i] will be 'Y'. | ||||||||||||
Examples | |||||||||||||
0) | |||||||||||||
| |||||||||||||
1) | |||||||||||||
|
大致题意:
<=16个人举办如图所示的淘汰赛,已给出每两个人之间对决的输赢结果矩阵
求对于每个人来说,有多少种安排位置方案使这个人最后获胜
思路:
状压DP,还是有点复杂的状压
对于第x个人最终获胜有多少种方式可以表示为dp[x][(1<<n)-1]
然后递归向下,枚举x能战胜的对手y
然后把集合S分为两半,一半包含x,一半包含y
则有:dp[x][S] += dp[x][S1]*dp[y][S2]*2(相对位置可以变)
枚举半个集合显然就是枚举子集,所以总的复杂度是O(n*3^n)
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <ctime>
#include <bitset>
#include <algorithm>
#define SZ(x) ((int)(x).size())
#define ALL(v) (v).begin(), (v).end()
#define foreach(i, v) for (__typeof((v).begin()) i = (v).begin(); i != (v).end(); ++ i)
#define reveach(i, v) for (__typeof((v).rbegin()) i = (v).rbegin(); i != (v).rend(); ++ i)
#define REP(i,n) for ( int i=1; i<=int(n); i++ )
#define rep(i,n) for ( int i=0; i<int(n); i++ )
using namespace std;
typedef long long ll;
#define X first
#define Y second
typedef pair<int,int> pii;
template <class T>
inline bool RD(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template <class T>
inline void PT(T x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9) pt(x / 10);
putchar(x % 10 + '0');
}
ll dp[20][1<<16];
int bit[1<<16];
int cal(int x){
int ans = 0;
while(x) ans += (x&1), x >>= 1;
return ans;
}
int n;
vector<string> mp;
ll DP(int u,int state){
ll &ans = dp[u][state];
if( ans != -1 ) return ans;
if( bit[state] == 2 ){
rep(v,n)
if( (1<<v)&state && mp[u][v] == 'Y')
return ans = 2;
return ans = 0;
}
ans = 0;
int c = (bit[state]-2)/2;
rep(v,n){
if( (1<<v)&state && mp[u][v] == 'Y' ){
int all = state & (~(1<<u)) & (~(1<<v));
for( int tmp = state; tmp ; tmp = (tmp-1)&all){
if( bit[tmp] != c) continue;
ans += 2*DP(u, ((1<<u)|tmp) )*DP(v, ((1<<v)|all)&(~tmp) );
}
}
}
return ans;
}
class CheeseRolling {
public:
vector<long long> waysToWin( vector <string> wins ) {
memset(dp,-1,sizeof(dp));
foreach(it,wins) mp.push_back(*it);
n = SZ(wins);
for(int i = 0; i < (1<<16);i++) bit[i] = cal(i);
vector<ll> ans;
rep(i,n) ans.push_back(DP(i,(1<<n)-1));
return ans;
}
};