刷题总结——树有几多愁(51nod1673 虚树+状压dp+贪心)
题目:
Input
第一行一个数n(1<=n<=100000)。
接下来n-1行,每行两个数ai,bi(1<=ai,bi<=n),表示存在一条边连接这两个点。
Output
一行表示答案
Input示例
5
1 2
2 4
2 3
3 5
Output示例
3
题解
挺神奇复杂的一道题···
首先是这道题的基本策略··容易想到贪心··我们尽量将小的数放在越靠近叶节点的地方···因为深度越小的点对所有叶节点的影响肯定是越大的····所以我们考虑每次先将一个节点子树填完后再填它本身··且它本身的编号一定是与子树中最大编号连续的···
另外由于只有20个叶节点··可以想到树上一定会有很多的链····对于链结合上面的策略我们可以相当链的编号一定是从链最下面的节点到上面严格递增的····因此我们可以将原树中的链全部省略掉···新建一个虚树··新的边为原来链的长度,由只有20个叶节点可以推出新的树的节点数不会多于100个··大大减少复杂度··
最后由20个叶节点可以想到状压dp····这是本题中最为复杂的地方···的
我们用f[i]表示我们选取了i状态叶节点下的乘积的最小值···首先由i状态我们可以确定有哪些节点的所在子树的叶节点是全部取到了的···由此该节点u所在子树到它在新树中的父亲节点的编号肯定是确定的(由基本策略可以推出编号肯定是已经填到了1——size[u]+len[u],size[u]为u所在子树大小,len[u]为它到它在新树中的父亲节点的边的长度)
设上面的范围为(1——t),那么接下来要填的叶子节点的编号肯定是t+1,此时我们只需枚举接下来要填的叶子节点是哪一个···然后用f[i]*(t+1)的值去更新f[i|(x)]即可,其中x为我们枚举的那一个叶子····
另外注意本题是要取模的··但为了在dp时比较大小我们需要准备两个dp数组··一个用于记录正确的取了模的答案··一个用于比较··比较的那个数组可以用log或者用double来比较(double的范围是很大的····1.7*10(308))
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
const int N=1e5+;
const int mod=1e9+;
int n,first[N],go[N*],next[N*],tot,cntlf,lf[],size[],cnt,lim,got[],len[];
long long dp[<<];
double f[<<];
bool islf[N],del[N];
vector<int>g[];
inline int R()
{
char c;int f=;
for(c=getchar();c<''||c>'';c=getchar());
for(;c<=''&&c>='';c=getchar()) f=(f<<)+(f<<)+c-'';
return f;
}
inline void comb(int a,int b)
{
next[++tot]=first[a],first[a]=tot,go[tot]=b;
next[++tot]=first[b],first[b]=tot,go[tot]=a;
}
inline void dfs1(int u,int fa)
{
int sum=;
for(int e=first[u];e;e=next[e])
{
int v=go[e];if(v==fa) continue;
sum++;dfs1(v,u);
}
if(!sum) islf[u]=true;
else if(sum==) del[u]=true;
}
inline void dfs2(int u,int fa,int tempfa,int templen)
{
templen++;
if(!del[u])
{
len[++cnt]=templen;templen=;
if(islf[u]) lf[++cntlf]=cnt;
if(tempfa) g[tempfa].push_back(cnt);
tempfa=cnt;
}
for(int e=first[u];e;e=next[e])
{
int v=go[e];if(v==fa) continue;
dfs2(v,u,tempfa,templen);
}
}
int main()
{
//freopen("a.in","r",stdin);
n=R();int a,b;
for(int i=;i<n;i++) a=R(),b=R(),comb(a,b);
dfs1(,);dfs2(,,,);
for(int i=;i<=cntlf;i++) size[lf[i]]=;
for(int i=cnt;i>=;i--)
for(int j=;j<g[i].size();j++) size[i]+=size[g[i][j]];
lim=(<<cntlf);dp[]=f[]=;
for(int i=;i<lim;i++)
{
int num=;
memset(got,,sizeof(got));
for(int j=;j<=cntlf;j++)
if(i&(<<(j-))) got[lf[j]]=;
for(int j=cnt;j>=;j--)
{
for(int k=;k<g[j].size();k++) got[j]+=got[g[j][k]];
if(got[j]==size[j]) num+=len[j];
}
double temp=f[i]*num;
for(int j=;j<=cntlf;j++)
if(!(i&(<<(j-)))&&temp>f[i|(<<(j-))])
f[i|(<<(j-))]=temp,dp[i|(<<(j-))]=(long long)dp[i]*num%mod;
}
cout<<dp[lim-]<<endl;
return ;
}
刷题总结——树有几多愁(51nod1673 虚树+状压dp+贪心)的更多相关文章
- 51nod1673 树有几多愁 - 贪心策略 + 虚树 + 状压dp
传送门 题目大意: 给一颗重新编号,叶子节点的值定义为他到根节点编号的最小值,求所有叶子节点值的乘积的最大值. 题目分析: 为什么我觉得这道题最难的是贪心啊..首先要想到 在一条链上,深度大的编号要小 ...
- 51nod 1673 树有几多愁——虚树+状压DP
题目:http://www.51nod.com/Challenge/Problem.html#!#problemId=1673 建一个虚树. 一种贪心的想法是把较小的值填到叶子上,这样一个小值限制到的 ...
- 刷题向》关于第一篇状压DP BZOJ1087 (EASY+)
这是本蒟蒻做的第一篇状压DP,有纪念意义. 这道题题目对状压DP十分友善,算是一道模板题. 分析题目,我们发现可以用0和1代表每一个格子的国王情况, 题目所说国王不能相邻放置,那么首先对于每一行是否合 ...
- 刷题总结——bzoj1725(状压dp)
题目: 题目描述 Farmer John 新买了一块长方形的牧场,这块牧场被划分成 N 行 M 列(1<=M<=12; 1<=N<=12),每一格都是一块正方形的土地. FJ ...
- 【62测试】【状压dp】【dfs序】【线段树】
第一题: 给出一个长度不超过100只包含'B'和'R'的字符串,将其无限重复下去. 比如,BBRB则会形成 BBRBBBRBBBRB 现在给出一个区间[l,r]询问该区间内有多少个字符'B'(区间下标 ...
- luogu4294 [WC2008]游览计划(状压DP/斯坦纳树)
link 题目大意:给定一个网格图,有些点是关键点,选择格点有代价,求把所有关键点联通的最小代价 斯坦纳树模板题 斯坦纳树问题:给定一个图结构,有一些点是关键点,求把这些关键点联通的最小代价e 斯坦纳 ...
- 【思维题 状压dp】APC001F - XOR Tree
可能算是道中规中矩的套路题吧…… Time limit : 2sec / Memory limit : 256MB Problem Statement You are given a tree wit ...
- [bzoj4006][JLOI2015]管道连接_斯坦纳树_状压dp
管道连接 bzoj-4006 JLOI-2015 题目大意:给定一张$n$个节点$m$条边的带边权无向图.并且给定$p$个重要节点,每个重要节点都有一个颜色.求一个边权和最小的边集使得颜色相同的重要节 ...
- 【BZOJ2595_洛谷4294】[WC2008]游览计划(斯坦纳树_状压DP)
上个月写的题qwq--突然想写篇博客 题目: 洛谷4294 分析: 斯坦纳树模板题. 简单来说,斯坦纳树问题就是给定一张有边权(或点权)的无向图,要求选若干条边使图中一些选定的点连通(可以经过其他点) ...
随机推荐
- thisnkphp添加二维码
Rcode二维码生成类QRcode.class.php实例演示 <?php //import('@.Org.QRcode');//thinkphp include_once('QRcode.cl ...
- HTML_2
html图像 <img>标签可以在网页上插入一张图片,它是独立使用的标签,通过‘src’属性定义图片的地址(可为绝对路径也可为相对路径),通过‘alt’属性定义图片加载时显示的文字,以及对 ...
- iOS或Mac开发者应该记住的前缀
- destoon 列表页面增加手动选择排序方式
在mobile/include/mall.inc.php 行60 $order = $MOD['order']; 之前增加 排序方式判断 如果有order参数则$order接受参数,没有就用默认 ...
- 8.Yii2.0框架控制器接收get.post数据
8.Yii2.0框架控制器接收get.post数据 一.get传参 <?php /** * Created by Haima. * Author:Haima * QQ:228654416 * D ...
- LeetCode(292) Nim Game
题目 You are playing the following Nim Game with your friend: There is a heap of stones on the table, ...
- 数学基础:HUD1124-Factorial(N!末尾0的个数)
Factorial Problem Description The most important part of a GSM network is so called Base Transceiver ...
- lwqq
源码安装lwqq 加密保存密码 发送截图
- Linux学习-延伸正则表达式
grep 默认仅支持基础正则表达式,如果要使用延伸型正则 表达式,你可以使用 grep -E , 不过更建议直接使用 egrep !直接区分指令比较好记忆!其 实 egrep 与 grep -E 是类 ...
- 数据挖掘算法——Apriori
在上一篇数据挖掘入门算法整理中提到,Apriori算法是关联规则算法中使用最为广泛的算法,这次我们就来学习下该算法的基本知识. 一.算法概述 Apriori 算法是一种最有影响力的挖掘布尔关联规则的频 ...