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



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