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 ...
随机推荐
- Java基础教程(14)--嵌套类
Java允许在一个类中定义另外一个类,这样的类被称为嵌套类,就像下面这样: class OuterClass { ... class NestedClass { ... } } 嵌套类分为两种 ...
- 手把手教你写一个java的orm(四)
开始准备生成sql 在上一篇里,我们已经取到了我们在生成sql语句中所需要的信息,这一篇里我们开始根据class来生成我们需要的sql.在这之前我们先确认几件事情 sql里的参数我们使用占位符的形式. ...
- Angular2学习笔记一
TypeScript: TypeScript变量声明:let和const是JavaScript里相对较新的变量声明方式,const是对let的一个增强,它能阻止对一个变量再次赋值. var作用域或函数 ...
- oracle逐步学习总结之oracle分页查询(基础三)
原创作品,转载请在文章开头明显位置注明出处:https://www.cnblogs.com/sunshine5683/p/10087205.html oracle 的分页有三种,下面将这三种方式一一列 ...
- vue+element ui 的tab 动态增减,切换时提示用户是否切换
前言:工作中用到 vue+element ui 的前端框架,动态添加 Tab,删除 Tab,切换 Tab 时提示用户是否切换等,发现 element ui 有一个 bug,这里记录一下如何实现.转载 ...
- Q:链表的中间元素
问题:如何得到一个链表的中间元素? 相信,这个问题对于刚入门编程的人来说,都不会难,最自然而然的想法是先遍历一遍链表,统计链表中的元素的个数,之后,再走一遍链表,所走的步长为链表长度的一半.这样就 ...
- JS基础(三)
25.使用JS操作CSS样式 DHTML表示动态HTML(Dynamic HTML,DHTML),不是标记语言,只是一种由微软提出的网页脚本化概念,目标是结合JS+HTML+CSS设计动态特效,得到很 ...
- CentOS7.4 + Hadoop2.9安装配置管理(分布式)
1. 规划 1.1. 机器列表 NameNode SecondaryNameNode DataNodes 192.168.1.121 192.168.1.122 192.168.1.101 192 ...
- android studio使用openssl
前言 逆向的基础是开发, 逆向分析时很多时候会使用一些公开的加密函数来对数据进行加密,通过使用 openssl 熟悉下. 正文 首先得先编译出来 openssl,然后把它们复制到你的工程目录下. in ...
- Pwn With longjmp
前言 这个是 seccon-ctf-quals-2016 的一个题,利用方式还是挺特殊的记录一下. 题目链接 http://t.cn/RnfeHLv 正文 首先看看程序的安全措施 haclh@ubun ...