bzoj1808 [Ioi2007]training 训练路径
Description
Input
Output
Sample Input
2 1 0
3 2 0
4 3 0
5 4 0
1 3 2
3 5 2
2 4 5
2 5 1
Sample Output
HINT

正解:状压$dp$。
这道题应该是去年某场考试考过的题,当时爆零了(似乎是因为没有小数据的暴力分。。
首先如果一条边的两个点在树上的路径长度为奇数,那么这条边肯定要删掉。
那么我们可以发现,这时存在偶环的充要条件就是一个环经过了任意两条非树边。
因为两个奇环通过公共边拼在一起,再把公共边挖掉,肯定是一个偶环。
所以这道题的限制就是不能出现这种情况,也就是说我们需要留下一棵仙人掌。
知道这个性质以后就不是那么难做了(虽然对于我来说还是很难
我们先把题意转化成用总边权减去最大留下的边权。
考虑一个条件,即每个点度数不超过$10$,这启发我们可以在树上维护儿子的状态。
于是考虑状压$dp$,设$f[i][S]$表示$i$这棵子树,不考虑状态$S$的集合的儿子(就是把这些儿子砍掉)的最大值。
我们考虑在$lca$处计算一条边的贡献,首先如果$lca$为$i$的所有边都不留,那么$f[i][S]=\sum f[son][S]$。
然后我们依次考虑每一条边必须加的贡献,对于每一条边,设两个端点为$a,b$(如果有一个为$lca$就把这个点丢掉)。
那么我们的贡献就是$w+f[a]+f[b]$再加上所有$a$到$b$路径上的每个点(不包括$a,b,lca$)不考虑它在路径上的儿子的状态。
很显然,这条路径不能被其他非树边覆盖,所以我们就必须把这条路径上的树边都断开,把一个点的贡献加上的时候不能考虑路径上的其他点。
所以这道题我们就做完了,复杂度为$O(m*2^{10}+mn)$。
#include <bits/stdc++.h>
#define il inline
#define RG register
#define ll long long
#define N (2005) using namespace std; vector<int> h[N]; struct E{ int u,v,w; }e[];
struct edge{ int nt,to; }g[N<<]; int f[N][N],st[N],sz[N],fa[N],son[N],top[N],tid[N],dep[N],head[N],n,m,num,sum,tot; il int gi(){
RG int x=,q=; RG char ch=getchar();
while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar();
while (ch>='' && ch<='') x=x*+ch-'',ch=getchar();
return q*x;
} il void insert(RG int from,RG int to){
g[++num]=(edge){head[from],to},head[from]=num; return;
} il void dfs1(RG int x,RG int p){
fa[x]=p,sz[x]=,dep[x]=dep[p]+;
for (RG int i=head[x],v;i;i=g[i].nt){
v=g[i].to; if (v==p) continue;
dfs1(v,x),sz[x]+=sz[v];
if (sz[son[x]]<=sz[v]) son[x]=v;
}
return;
} il void dfs2(RG int x,RG int p,RG int anc){
top[x]=anc; if (son[x]) dfs2(son[x],x,anc);
for (RG int i=head[x],v;i;i=g[i].nt){
v=g[i].to; if (v!=p && v!=son[x]) dfs2(v,x,v);
}
return;
} il int lca(RG int u,RG int v){
while (top[u]!=top[v]){
if (dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v] ? u : v;
} il void dfs(RG int x,RG int p){
RG int tot=,sum;
for (RG int i=head[x];i;i=g[i].nt) if (g[i].to!=p) dfs(g[i].to,x);
for (RG int i=head[x];i;i=g[i].nt) if (g[i].to!=p) tid[g[i].to]=<<tot,st[tot++]=g[i].to;
for (RG int i=(<<tot)-;~i;--i){
sum=; for (RG int j=;j<tot;++j) if (!(i>>j&)) sum+=f[st[j]][]; f[x][i]=sum;
}
for (RG int i=,a=,b=,id,S=h[x].size();i<S;++i,a=b=){
id=h[x][i],sum=e[id].w;
if (e[id].u!=x) for (sum+=f[a=e[id].u][];fa[a]!=x;a=fa[a]) sum+=f[fa[a]][tid[a]];
if (e[id].v!=x) for (sum+=f[b=e[id].v][];fa[b]!=x;b=fa[b]) sum+=f[fa[b]][tid[b]];
for (RG int j=(<<tot)-;~j;--j)
if (!(j&tid[a]) && !(j&tid[b])) f[x][j]=max(f[x][j],sum+f[x][j|tid[a]|tid[b]]);
}
return;
} int main(){
#ifndef ONLINE_JUDGE
freopen("training.in","r",stdin);
freopen("training.out","w",stdout);
#endif
n=gi(),m=gi();
for (RG int i=,u,v,w;i<=m;++i){
u=gi(),v=gi(),w=gi(),sum+=w;
if (w) e[++tot]=(E){u,v,w};
if (!w) insert(u,v),insert(v,u);
}
dfs1(,),dfs2(,,);
for (RG int i=,G;i<=tot;++i){
G=lca(e[i].u,e[i].v);
if (!((dep[e[i].u]+dep[e[i].v]-(dep[G]<<))&)) h[G].push_back(i);
}
dfs(,),cout<<sum-f[][]; return ;
}
bzoj1808 [Ioi2007]training 训练路径的更多相关文章
- [IOI2007]训练路径
Description 马克(Mirko)和斯拉夫克(Slavko)正在为克罗地亚举办的每年一次的双人骑车马拉松赛而紧张训练.他们需要选择一条训练路径. 他们国家有N个城市和M条道路.每条道路连接两个 ...
- 树形dp专题总结
树形dp专题总结 大力dp的练习与晋升 原题均可以在网址上找到 技巧总结 1.换根大法 2.状态定义应只考虑考虑影响的关系 3.数据结构与dp的合理结合(T11) 4.抽直径解决求最长链的许多类问题( ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- NOIP前的刷题记录
因为这几天要加油,懒得每篇都来写题解了,就这里记录一下加上一句话题解好了 P4071 [SDOI2016]排列计数 组合数+错排 loj 6217 扑克牌 暴力背包 P2511 [HAOI2008 ...
- Kaldi单音素模型 训练部分
在Kaldi中,单音素GMM的训练用的是Viterbi training,而不是Baum-Welch training.因此就不是用HMM Baum-Welch那几个公式去更新参数,也就不用计算前向概 ...
- kaldi基于GMM的单音素模型 训练部分
目录 1. gmm-init-mono 模型初始化 2. compile-train-graghs 训练图初始化 3. align-equal-compiled 特征文件均匀分割 4. gmm-acc ...
- captcha_trainer 验证码识别-训练 使用记录
captcha_trainer 验证码识别-训练 使用记录 在爬数据的时候,网站出现了验证码,那么我们就得去识别验证码了.目前有两种方案 接入打码平台(花钱,慢) 自己训练(费时,需要GPU环境,快) ...
- 使用SSD检测框架训练自己的数据
数据集做好后,训练程序为/examples/ssd/ssd_pascal.py,运行之前,我们需要修改相关路径代码,主要是训练路径的修改和关于自己数据集参数的一些修改. cd /examples/ss ...
- 训练集(train set) 验证集(validation set) 测试集(test set)。
训练集(train set) 验证集(validation set) 测试集(test set). http://blog.sina.com.cn/s/blog_4d2f6cf201000cjx.ht ...
随机推荐
- Vertica示例数据库安装
1.示例数据库简介: Vertica跟传统数据库一样,自带了示例数据库--VMart示例数据库,是一个多架构数据库.该数据是大型超市(VMart)中可能会用到的数据库,可用来访问产品.客户.员工以及网 ...
- 有序列表ol和定义列表dl,dt,dd
有序列表是一种讲究排序列表结构,使用<ol>标签定义,其中包含多个<li>列表项目.一般网页设计中,列表结构可以互用有序或者无序类表标签.但是,在强调项目排序栏目中,选用有序列 ...
- Hibernate中一级缓存概念以及flush与clear的区别
Hibernate采用缓存机制提高数据查询效率.缓存分为一级缓存和二级缓存,一级缓存在Session中存在,二级缓存需要手动配置. 在一级缓存中,如果数据保存到数据库中后,而session又没有关闭的 ...
- 热更新--动态加载framework
1.准备工作:先自己封装一个framework:http://www.cnblogs.com/sunjianfei/p/5781863.html 2.把封装好的framework压缩成zip,放到本地 ...
- 1 springboot创建项目
文章采用idea工具进行springboot项目创建 1点击 New Project 选择[Spring Initializr] 选择Jdk版本其他默认即可 点击Next 2添加项目信息 文章即使用默 ...
- PHP报错Deprecated: Function ereg_replace() is deprecated in
可能用了PHP5.3乃至更高的PHP版本,目前DEDE中有很多地方的正则函数都用的ereg_replace,而这个函数现在在PHP5.3中已经被废止了. 解决办法: 如果一定要用php5.3,请修改p ...
- vue图片上传及java存储图片(亲测可用)
1.前言 在使用elementui的upload组件时,我一直无法做到上传的图片和其他数据一起提交.单纯的上传文件,java的存储图片的方式也有局限性. 我知道的后端保存图片有两种方式:一种是直接存储 ...
- java里 equals和== 区别
1.java中equals和==的区别 值类型是存储在内存中的堆栈(简称栈),而引用类型的变量在栈中仅仅是存储引用类型变量的地址,而其本身则存储在堆中.2.==操作比较的是两个变量的值是否相等,对于引 ...
- sql 中的注释
1.单行注释 “-- ” 即:两个中滑线加一个空格 2.多行注释 "/* ... */" 示例: -- 单行注释 /* 多行注释*/ create table test(id i ...
- 2cmd 窗口 javac 错误:编码GBK的不可映射字符
错误截图: 解决办法:第一步 第二步: