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 ...
随机推荐
- ubuntu上使用vim编辑文本内容
1. 什么是 vim? Vim是从 vi 发展出来的一个文本编辑器.代码补完.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用.简单的来说, vi 是老式的字处理器,不过功能已经很齐全了, ...
- T-SQL学习的笔记,以备查阅
create database MyDatabseOne; --创建数据库 drop database MydatabaseOne; --删除数据库; --如果直接点"执行"将是执 ...
- Java基础教程(12)--深入理解类
一.方法的返回值 当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...
- 面向对象(static关键字的特点)
static关键字的特点 * a:随着类的加载而加载 * b:优先于对象存在 * c:被类的所有对象共享 * 举例:咱们班级的学生应该共用同一个班级编号. * 其实这个特点也是在告诉我们什么时候使用静 ...
- Graphviz 的命令行参数说明
所有的Graphviz程序都具有相似的命令行调用方式 cmd [ flags] [input files] 如果没有指定输入文件路径程序从标准输入stdin中读取. 参数设置 -Gname ...
- js 中使用 #region #endregion
vs 和 vs code 都是可以支持 js 使用 #region 折叠代码的:code 我就不说了 同理vs 的: 首先下载 vs 插件,插件路径:https://archive.codeplex. ...
- 洛谷P4027 [NOI2007]货币兑换(dp 斜率优化 cdq 二分)
题意 题目链接 Sol 解题的关键是看到题目里的提示... 设\(f[i]\)表示到第\(i\)天所持有软妹币的最大数量,显然答案为\(max_{i = 1}^n f[i]\) 转移为\(f_i = ...
- javascript数组元素全排列
多个数组(数量不定)例如三个数组 {a,b} {1,2} {d}排列组合后为a,1,da,2,db,1,db,2,d是js的算法哦 var arr = [["a","b& ...
- 计时器(Chronometer)
计时器(Chronometer) 常用属性:format(计时器的计时格式) 常用方法: setBase(long base) 设置计时器的起始时间 setFormat(String format) ...
- PyQt4(使用ui)
1.使用qt designer设计界面,保存为test1.ui: 2.使用pyuic4 test1.ui -o ui.py生成ui代码. 3.程序载入. import sys import ui fr ...