程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> HDU 4275 Color the Tree 樹的不重復染色 求樹的中心+hash

HDU 4275 Color the Tree 樹的不重復染色 求樹的中心+hash

編輯:C++入門知識

題意:給定n(n<=50000)個點組成的樹,用m(m<=100000)種顏色染色,問不重復(通過旋轉)的染色方法數有多少種。
題解:這題完全是看人家的代碼看懂的唉…
         首先找到樹的中心(不是重心),中心的定義是樹的直徑的中點,如果直徑上節點個數是偶數,那麼在中間建立一個新的節點。
         然後從中心dfs,對於每一棵子樹得到相應的hash值(hash方法:hash[i]= A * (hash[j1]*B)^hash[j2]*B.....^hash[jn]*C%D;(順序執行)),
         排序之後同構的子樹一定是排列在相鄰的位置,這樣通過隔板法解x1+x2+……+xans[i] = cnt得到染當前形狀子樹的方法數,然後得到最後的答案。
         下面簡單說說取中點dfs的正確性:
         定義性質x:以u節點為根節點fa為u的father節點時,任意hash[son]都不等於hash[fa](上方子樹的hash值)。
         如果取中點dfs那麼對於dfs到的所有節點上面的性質都滿足,定義longest[i]為以i為根節點到葉子節點的最大距離,l為樹的直徑。
         因為longest[fa](上方子樹 && fa != 中心)>=l/2,longest[i]< l/2,所以滿足性質x,這樣就能保證正確性,不會把同構的子樹遺漏掉。

Sure原創,轉載請注明出處。
[cpp] 
#include <iostream> 
#include <cstdio> 
#include <memory.h> 
#include <algorithm> 
using namespace std; 
const int maxn = 50005; 
const int maxm = 100002; 
const int leaf = 9778972; 
const int yin = 10003; 
const int yy = 131237; 
const int mod = 1000000007; 
struct node 

    int v; 
    int next; 
}edge[maxn << 1]; 
struct H 

    __int64 hash,ans; 
    bool operator < (const H &other) const 
    { 
        return hash < other.hash; 
    } 
}val[maxn]; 
int head[maxn],down[maxn],longest[maxn]; 
__int64 ans[maxn],hash[maxn],A[maxm]; 
int m,n,bj,idx,root,path; 
 
void prepare() 

    A[0] = A[1] = 1; 
    for(int i=2;i<maxm;i++) 
    { 
        A[i] = A[i-1] * i; 
        A[i] %= mod; 
    } 
    return; 

 
void init() 

    memset(head,-1,sizeof(head)); 
    memset(down,-1,sizeof(down)); 
    idx = path = 0; 
    bj = root = -1; 
    return; 

 
void addedge(int u,int v) 

    edge[idx].v = v; 
    edge[idx].next = head[u]; 
    head[u] = idx++; 
 
    edge[idx].v = u; 
    edge[idx].next = head[v]; 
    head[v] = idx++; 
    return; 

 
void read() 

    int u,v; 
    for(int i=1;i<n;i++) 
    { 
        scanf("%d %d",&u,&v); 
        addedge(u,v); 
    } 
    return; 

 
__int64 powmi(__int64 a,int x) 

    __int64 res = 1; 
    while(x) 
    { 
        if(x & 1) 
        { 
            res *= a; 
            res %= mod; 
        } 
        a *= a; 
        a %= mod; 
        x >>= 1; 
    } 
    return res; 

 
__int64 C(__int64 n,int m) 

    if(n == 1LL * m) return 1LL; 
    __int64 res = 1; 
    for(int i=1;i<=m;i++) 
    { 
        res *= 1LL * (n - i + 1); 
        res %= mod; 
    } 
    res *= powmi(A[m] , mod-2); 
    return res % mod; 

 
void DFS(int st,int pre) 

    int l = 0,ll = 0; 
    for(int i=head[st];i != -1;i=edge[i].next) 
    { 
        if(edge[i].v == pre) continue; 
        DFS(edge[i].v , st); 
        if(longest[edge[i].v] > l) 
        { 
            ll = l; 
            l = longest[edge[i].v]; 
            down[st] = i; 
        } 
        else if(longest[edge[i].v] > ll) ll = longest[edge[i].v]; 
    } 
    if(l + ll + 1 > path) 
    { 
        path = l + ll + 1; 
        root = st; 
    } 
    longest[st] = l + 1; 
    return; 

 
void make() 

    DFS(1,0); 
    if(path & 1) 
    { 
        while(longest[root] * 2 - 1 > path) 
        { 
            root = edge[down[root]].v; 
        } 
        ans[root] = 1LL * m; 
    } 
    else 
    { 
        while(longest[root] * 2 - 2 > path) 
        { 
            root = edge[down[root]].v; 
        } 
        addedge(root , ++n); 
        addedge(n , edge[down[root]].v); 
        bj = down[root]; 
        root = n; 
        ans[root] = 1LL; 
    } 
    return; 

 
void dfs(int st,int pre) 

    int num = 0; 
    for(int i=head[st];i != -1;i=edge[i].next) 
    { 
        if(edge[i].v == pre) continue; 
        if(bj != -1 && (i == bj || i == (bj ^ 1))) continue; 
        num++; 
        ans[edge[i].v] = 1LL * m; 
        dfs(edge[i].v , st); 
    } 
    if(num == 0) 
    { 
        hash[st] = leaf; 
        return; 
    } 
    int c = 0; 
    for(int i=head[st];i != -1;i=edge[i].next) 
    { 
        if(edge[i].v == pre) continue; 
        if(bj != -1 && (i == bj || i == (bj ^ 1))) continue; 
        val[c].hash = hash[edge[i].v]; 
        val[c++].ans = ans[edge[i].v]; 
    } 
    sort(val , val + num); 
    hash[st] = leaf; 
    for(int i=0;i<num;) 
    { 
        int j = i; 
        for(;j<num && val[i].hash == val[j].hash;j++) 
        { 
            hash[st] *= yin; 
            hash[st] ^= val[j].hash; 
            hash[st] %= mod; 
        } 
        hash[st] = hash[st] * yy % mod; 
        ans[st] *= C(val[i].ans + j - i - 1, j - i); 
        ans[st] %= mod; 
        i = j; 
    } 
    return; 

 
int main() 

    prepare(); 
    while(~scanf("%d %d",&n,&m)) 
    { 
        init(); 
        read(); 
        make(); 
        dfs(root , 0); 
        printf("%I64d\n",ans[root]); 
    } 
    return 0; 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved