[51nod 1673] 樹有幾多愁

題目連接html

顯然必定存在最優解知足編號小的節點深度越深,即從小到大的優先選擇(葉節點|除本身之外子樹節點都已經被標號)的節點標號(影響最小),存在取法(順序)獲得最優解。c++

所以考慮對葉節點狀壓,轉移過程當中須要計算出當前已經被直接或間接地肯定的節點的數量c做爲下一個葉節點的編號。複雜度O((n+n)2^20)是不行的spa

但考慮到葉子節點不過20個,則虛樹(葉子節點是關鍵點)總結點不過40個,所以利用序樹加速就行了。code

#include <bits/stdc++.h>
using namespace std;

const int N=1e5+3;
const int P=1e9+7;

int n,m,cnt;
int fa[41],val[41],siz[41],id[21];
vector<int> G[N];

int f[1<<20],t[41];
double g[1<<20];

void dfs(int x,int p,int d,int w) {
    if(G[x].size()==2) {
        for(int y:G[x]) if(y!=p) dfs(y,x,d,w+(d!=0));
        return;
    }
    cnt++; fa[cnt]=d; 
    siz[cnt]=val[cnt]=w; d=cnt;
    if(G[x].size()==1) id[m++]=d;
    for(int y:G[x]) if(y!=p) dfs(y,x,d,1);
    siz[fa[d]]+=siz[d];
}

int main() {
    scanf("%d",&n);
    for(int x,y,i=n; --i; ) {
        scanf("%d%d",&x,&y);
        G[x].push_back(y);
        G[y].push_back(x);
    }
    G[1].push_back(0);
    dfs(1,0,0,1);
    memset(f,-0x3f,sizeof f);
    memset(g,-0x7f,sizeof g);
    f[0]=1; g[0]=1;
    for(int s=0; s<(1<<m); ++s) {
        int now=0;
        memset(t,0,sizeof t);
        for(int x=0; x<m; ++x) if(!((s>>x)&1)) t[id[x]]=-1;
        for(int x=cnt; x; --x) {
            if(t[x]==siz[x]-val[x]) now+=val[x],t[x]+=val[x];
            t[fa[x]]+=t[x];
        }
        for(int x=0; x<m; ++x) if(!((s>>x)&1)) {
            if(g[s|(1<<x)]<g[s]*(now+1)) {
                g[s|(1<<x)]=g[s]*(now+1);
                f[s|(1<<x)]=1LL*f[s]*(now+1)%P;
            }
        }
    }
    printf("%d\n",f[(1<<m)-1]);
    return 0;
}
相關文章
相關標籤/搜索