刷题总结——树有几多愁(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 分析: 斯坦纳树模板题. 简单来说,斯坦纳树问题就是给定一张有边权(或点权)的无向图,要求选若干条边使图中一些选定的点连通(可以经过其他点) ...
随机推荐
- codeforce Gym 100500A Poetry Challenge(博弈,暴搜)
题解:状态压缩之后,暴力dfs,如果有一个选择,能让对手必败,那么就是必胜态,能转移到的状态都是对手的必胜态,或者无法转移,就是必败态. 总算是过了,TLE是因为状态没判重. #include< ...
- Android(java)学习笔记120:BroadcastReceiver之 应用程序安装和卸载 的广播接收者
国内的主流网络公司(比如网易.腾讯.百度等等),他们往往采用数据挖掘技术获取用户使用信息,从而采用靶向营销.比如电脑上,我们浏览网页的时候,往往会发现网页上会出现我们之前经常浏览内容的商业广告,这就是 ...
- Spring boot 集成ActiveMQ(包含双向队列实现)
集百家之长,成一家之言. 1. 下载ActiveMQ https://mirrors.tuna.tsinghua.edu.cn/apache/activemq/5.15.9/apache-activ ...
- Bootstrap历练实例:标签修饰
您可以使用修饰的 class label-default.label-primary.label-success.label-info.label-warning.label-danger 来改变标签 ...
- 【前端_js】JavaScript知识点总结
1.JavaScript的定义及特性 1.1.定义 javascript是运行在客户端的一种直译式脚本语言(程序在运行过程中逐行进行解释),它的解释器被称为JavaScript引擎,为浏览器的一部分. ...
- php curl使用例子
PHP支持的由Daniel Stenberg创建的libcurl库允许你与各种的服务器使用各种类型的协议进行连接和通讯.libcurl目前支持http.https.ftp.gopher.telnet. ...
- linux关于进程、内存和cpu情况
1.load average: 2.03, 1.76, 1.80 1分钟.5分钟.15分钟平均负载 2.%Cpu(s):100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa ...
- tp5使用外部类的三种方法
在tp5中使用外部类的时候有三种方法 第一种就是通过composer下载,通过这种方式下载的外部类能够支持自动加载,我们只要在使用的时候use一下命名空间就可以使用了 比如:我们的tp5第四季项目要使 ...
- 1、python-初探
语言包括编译型语言和解释型语言编译型:全部翻译,再执行:c.c++解释型:边执行边翻译:python.php.java.c#.perl.ruby.javascript 一.系统位数32位系统内存的最大 ...
- (转).gitignore详解
本文转自http://sentsin.com/web/666.html 今天讲讲Git中非常重要的一个文件——.gitignore. 首先要强调一点,这个文件的完整文件名就是“.gitignore”, ...