zoukankan      html  css  js  c++  java
  • [51nod 1673] 树有几多愁

    题目链接

    显然一定存在最优解满足编号小的节点深度越深,即从小到大的优先选择(叶节点|除自己以外子树节点都已经被标号)的节点标号(影响最小),存在取法(顺序)得到最优解。

    因此考虑对叶节点状压,转移过程中需要计算出当前已经被直接或间接地确定的节点的数量c作为下一个叶节点的编号。复杂度O((n+n)2^20)是不行的

    但考虑到叶子节点不过20个,则虚树(叶子节点是关键点)总结点不过40个,因此利用序树加速就好了。

    #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
    ",f[(1<<m)-1]);
    	return 0;
    }
    
  • 相关阅读:
    POJ 3253 Fence Repair
    POJ 2431 Expedition
    NYOJ 269 VF
    NYOJ 456 邮票分你一半
    划分数问题 DP
    HDU 1253 胜利大逃亡
    NYOJ 294 Bot Trust
    NYOJ 36 最长公共子序列
    HDU 1555 How many days?
    01背包 (大数据)
  • 原文地址:https://www.cnblogs.com/nosta/p/11027309.html
Copyright © 2011-2022 走看看