POJ 1241 Knockout Tournament

Knockout Tournament

Tree DP 。很有意思的一个题目。给定了2^n个人每轮比赛的结果,然后推测每个人可能的最高排名与最低排名。由于给的是每轮比赛的结果,所以题目在数据的读入与处理方面比较麻烦。如果编号为i的人赢了编号为j的人,那么我们连有向边(i,j),即j为i的孩子。这样我们只需要处理出每轮比赛的两个人之间的关系即可。由于数据的最后一个肯定是树的根节点,然后我们从后往前扫,我们就知道每一对数之间的关系了。此外我们需要将那些不在给的数据中的节点也给添加边关系。我们先计算出每个人祖先节点的个数,以及子孙节点的个数(也就是最高排名与最低排名)。对于每个查询,我们直接输出结果。

/*
 *author    : csuchenan
 *prog      : 1241
 *Algorithm : Tree DP DFS
 *notice    : build the tree
 *csuchenan	1241	Accepted	188K	16MS	C++	2033B
*/

#include <cstdio>
#include <cstring>
#include <vector>
using std::vector ;
#define maxn 270
vector<int> G[maxn] ;
int dp[maxn] ;
int son[maxn] ;
int n ;
int total[maxn] ;
int root ;

void init(){
    int num = 1<<n ;
    for(int i = 1 ; i <= num ; i ++){
        G[i].clear() ;
    }
    memset(dp , 0 , sizeof(dp)) ;
    memset(son , 0 , sizeof(son)) ;
}

bool read(){
    scanf("%d" , &n) ;
    if(n == 0)
        return 0 ;
    int num = 1 ;
    num = 1<< n ;
    num = num - 1 ;
    init() ;
    for(int i = 1 ; i <= num ; i ++){
        scanf("%d" , &total[i]) ;
    }
    root = total[num] ;
    for(int i = num - 1 ; i >= 1 ; i = i - 2){
        G[ total[i] ].push_back( total[i - 1] ) ;
        G[ total[i - 1] ].push_back( total[i] ) ;
    }
    for(int i = 1 ; i <= (num + 1)>>1  ; i ++){
        if(total[i]%2){
            G[total[i]].push_back(total[i] + 1) ;
            G[total[i] + 1].push_back(total[i]) ;
        }
        else{
            G[total[i]].push_back(total[i] - 1) ;
            G[total[i] - 1].push_back(total[i]) ;
        }
    }
    return n ;
}
void debug(){
    int num = 1 ;
    int i = n   ;
    num = 1<<n ;
    for(int i = 1 ; i <= num ; i ++){
        printf("%d : " , i) ;
        for(int j = 0 ; j != G[i].size() ; j ++){
            printf(" %d " , G[i][j]) ;
        }
        printf("\n") ;
    }
}

void dfs(int v , int f){
    dp[v] = dp[f] + 1 ;
    for(int i = 0 ; i != G[v].size() ; i ++){
        int u = G[v][i] ;
        if(u == f)
            continue ;
        dfs(u , v) ;
        son[v] += son[u] + 1 ;
    }
}

void solve(){
    dp[0] = 0 ;
    dfs(root , 0) ;

    int Q ;
    int x ;
    scanf("%d" , &Q) ;
    for(; Q-- ;){
        scanf("%d" , &x) ;
        printf("Player %d can be ranked as high as %d or as low as %d.\n" , x , dp[x] , (1<<n) - son[x] ) ;
    }
    printf("\n") ;
}
int main(){
    while(read()){
        //debug() ;
        solve() ;
    }
    return 0 ;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章