Topcoder SRM 663 Div2 Hard: CheeseRolling(状压DP)

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.


Topcoder SRM 663 Div2 Hard: CheeseRolling(状压DP)_第1张图片


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 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 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

 
Class: CheeseRolling
Method: waysToWin
Parameters: vector
Returns: vector
Method signature: vector waysToWin(vector wins)
(be sure your method is public)

Limits

 
Time limit (s): 4.000
Memory limit (MB): 256
Stack limit (MB): 256

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)  
 
{"NN",
 "YN"}
Returns: {0, 2 }
There are 2 ways to assign the players:
  • Player 0 goes to position 0 and player 1 goes to position 1.
  • Player 1 goes to position 0 and player 0 goes to position 1.
In both assignments, player 1 will win the match against player 0 because wins[1][0] = 'Y'.
1)  
 
{"NYNY",
 "NNYN",
 "YNNY",
 "NYNN"}
Returns: {8, 0, 16, 0 }




大致题意:

<=16个人举办如图所示的淘汰赛,已给出每两个人之间对决的输赢结果矩阵

求对于每个人来说,有多少种安排位置方案使这个人最后获胜


思路:

状压DP,还是有点复杂的状压

对于第x个人最终获胜有多少种方式可以表示为dp[x][(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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#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 pii;

template 
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 
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 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< waysToWin( vector  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 ans;
        rep(i,n) ans.push_back(DP(i,(1<





你可能感兴趣的:(状压DP)