码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-08-08 18:18:27      阅读:159      评论:0      收藏:0      [点我收藏+]

标签:

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

 
Class: CheeseRolling
Method: waysToWin
Parameters: vector <string>
Returns: vector<long long>
Method signature: vector<long long> waysToWin(vector <string> 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<<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;
   }
};





版权声明:本文为博主原创文章,未经博主允许不得转载。

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

标签:

原文地址:http://blog.csdn.net/kalilili/article/details/47360187

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!