【BZOJ1040】[ZJOI2008] 骑士(基环外向树DP)
大致题意: 给你一片基环外向树森林,如果选定了一个点,就不能选择与其相邻的节点。求选中点的最大权值和。
树形\(DP\)
此题应该是 树形\(DP\) 的一个升级版:基环外向树\(DP\)。
什么是基环外向树森林
什么是 基环外向树?
基环外向树,一般指一张 点数与边数相等 的联通图,此时必然存在一个环,若把这个环当成一个节点,则原图就形成了一棵树。
什么是 基环外向树森林?
一张由若干个基环外向树组成的图(此时 点数仍然等于边数),就是基环外向树森林。
基环外向树\(DP\)
那么,基环外向树\(DP\) 应该怎么写呢?
不难发现,对于某一棵基环外向树,只要去掉环上的一条边,它就成为一棵普通的树了。
所以,我们就随便去掉环上的一条边。
然后分别以 这条边连接的两个端点 为根,跑 树形\(DP\)。
这棵基环外向树的贡献就是两次\(DP\)结果的较大值。
要注意的是,由于这两个端点被一条边连接了,因此这两个端点不能同时选择。
具体内容还是看代码吧。
代码
#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define uint unsigned int
#define LL long long
#define ull unsigned long long
#define swap(x,y) (x^=y,y^=x,x^=y)
#define abs(x) ((x)<0?-(x):(x))
#define INF 1e9
#define N 1000000
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].Exist=1)
using namespace std;
LL n,rt,Size=1,ee=0,lnk[N+5],Val[N+5];
struct edge
{
LL to,nxt,Exist;
}e[2*N+5];
class FIO
{
private:
#define Fsize 100000
#define tc() (FinNow==FinEnd&&(FinEnd=(FinNow=Fin)+fread(Fin,1,Fsize,stdin),FinNow==FinEnd)?EOF:*FinNow++)
#define pc(ch) (FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,FoutSize,stdout),Fout[(FoutSize=0)++]=ch))
LL f,FoutSize,OutputTop;char ch,Fin[Fsize],*FinNow,*FinEnd,Fout[Fsize],OutputStack[Fsize];
public:
FIO() {FinNow=FinEnd=Fin;}
inline void read(LL &x) {x=0,f=1;while(!isdigit(ch=tc())) f=ch^'-'?1:-1;while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));x*=f;}
inline void read_char(char &x) {while(isspace(x=tc()));}
inline void read_string(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,!isspace(ch=tc())) if(!~ch) return;}
inline void write(LL x) {if(!x) return (void)pc('0');if(x<0) pc('-'),x=-x;while(x) OutputStack[++OutputTop]=x%10+48,x/=10;while(OutputTop) pc(OutputStack[OutputTop]),--OutputTop;}
inline void write_char(char x) {pc(x);}
inline void write_string(string x) {register LL i,len=x.length();for(i=0;i<len;++i) pc(x[i]);}
inline void end() {fwrite(Fout,1,FoutSize,stdout);}
}F;
class Class_FindCircle//找环
{
public:
LL L,R,Edge,vis[N+5];
inline void Solve(LL x,LL lst)
{
register LL i;
for(vis[x]=1,i=lnk[x];i;i=e[i].nxt)
{
if(!(e[i].to^lst)) continue;
vis[e[i].to]?(void)(L=x,R=e[i].to,Edge=i):Solve(e[i].to,x);//如果已经访问过这条边连接的另一个节点,就说明找到了环上的一条边,将其存储下来
}
}
}FindCircle;
class Class_TreeDP//树形DP
{
private:
LL f[N+5][2];
public:
inline void DP(LL x,LL lst,LL CanNot)
{
register LL i;
for(f[x][0]=0,f[x][1]=x^CanNot?Val[x]:0,i=lnk[x];i;i=e[i].nxt)
{
if(!(e[i].to^lst)||!e[i].Exist) continue;
DP(e[i].to,x,CanNot),f[x][0]+=max(f[e[i].to][0],f[e[i].to][1]),f[x][1]+=f[e[i].to][0];//状态转移
}
}
inline LL GetAns(LL x)
{
return max(f[x][0],f[x][1]);
}
}TreeDP;
int main()
{
register LL i,x,y,ans=0,res1,res2;
for(F.read(n),i=1;i<=n;++i) F.read(Val[i]),F.read(x),add(x,i),add(i,x);
for(i=1;i<=n;++i)
{
if(FindCircle.vis[i]) continue;//如果这个节点所在的基环外向树已经访问过了,就跳过当前节点
FindCircle.Solve(i,0),e[FindCircle.Edge].Exist=e[((FindCircle.Edge-1)^1)+1].Exist=0,//找到环上的一条边,并将这条边删去
TreeDP.DP(FindCircle.L,0,FindCircle.R),res1=TreeDP.GetAns(FindCircle.L),TreeDP.DP(FindCircle.R,0,FindCircle.L),res2=TreeDP.GetAns(FindCircle.R),//分别以两个端点为根,跑树形DP
ans+=max(res1,res2);//这棵基环外向树对答案的贡献就是两次DP的结果的较大值
}
return F.write(ans),F.end(),0;
}
【BZOJ1040】[ZJOI2008] 骑士(基环外向树DP)的更多相关文章
- 1040: [ZJOI2008]骑士~基环外向树dp
Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火绵延五百里,在和平环境中 ...
- [bzoj] 1040 骑士 || 基环外向树dp
原题 给出n个点n条边和每个点的点权,一条边的两个断点不能同时选择,问最大可以选多少. //图是一张基环外向树森林 是不是很像舞会啊- 就是多了一条边. 所以我们考虑一下对于一棵基环外向树,拆掉一条在 ...
- BZOJ1040: [ZJOI2008]骑士(奇环树,DP)
题目: 1040: [ZJOI2008]骑士 解析: 假设骑士\(u\)讨厌骑士\(v\),我们在\(u\),\(v\)之间连一条边,这样我们就得到了一个奇环树(奇环森林),既然是一颗奇环树,我们就先 ...
- HYSBZ 1040 骑士 (基环外向树DP)
Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火绵延五百里,在和平环境中 ...
- 初涉基环外向树dp&&bzoj1040: [ZJOI2008]骑士
基环外向树dp竟然如此简单…… Description Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发 ...
- [BZOJ 1040] [ZJOI2008] 骑士 【基环+外向树DP】
题目链接:BZOJ - 1040 题目分析 这道题目的模型就是一个图,不一定联通,每个连通块的点数等于边数. 每个连通块都是一个基环+外向树.即树上增加了一条边. 如果是树,就可以直接树形DP了.然而 ...
- BZOJ1040 骑士 基环外向树
1040: [ZJOI2008]骑士 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 6421 Solved: 2544[Submit][Status ...
- [BZOJ1040][ZJOI2008]骑士 基环树DP
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1040 题目给出了$n$个点和$n$条无向边,即一棵基环树或者基环树森林. 如果题目给的关系 ...
- BZOJ1040 [ZJOI2008]骑士 基环树林(环套树) 树形动态规划
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题意概括 有n个人,每一个人有一个最恨的人. 并且,每一个人有一个权值. 一个人不可以和他最恨的人同时被选中. 现在请你求出在 ...
随机推荐
- Spark内核概述
提交Spark程序的机器一般一定和Spark集群在同样的网络环境中(Driver频繁和Executors通信),且其配置和普通的Worker一致 1. Driver: 具有main方法的,初始化 Sp ...
- 洛谷P1083 借教室
P1083 借教室 题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借 ...
- 洛谷P1312 Mayan游戏
P1312 Mayan游戏 题目描述 Mayan puzzle是最近流行起来的一个游戏.游戏界面是一个 7 行5 列的棋盘,上面堆放着一些方块,方块不能悬空堆放,即方块必须放在最下面一行,或者放在其他 ...
- 多实例:MySQL系列之二
MySQL的多实例配置 在一台物理机中需要多个测试环境,那么就需要用到了搭建数据库的多个实例,多个实例的意思就是运行多份程序,实例与实例之间没有影响.要注意监听的端口需要不同. 环境:CentOS ...
- 008-数据类型(Dictionary)
数据类型(Dictionary) 一.定义 字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值 key=>value 对用冒号:分割,每个键值对之间用逗号,分割,整个字典包括在花括 ...
- Scrapy框架中的Pipeline组件
简介 在下图中可以看到items.py与pipeline.py,其中items是用来定义抓取内容的实体:pipeline则是用来处理抓取的item的管道 Item管道的主要责任是负责处理有蜘蛛从网页中 ...
- web.xml中监听器如何顺序加载
最近用到在Tomcat服务器启动时自动加载数据到缓存,这就需要创建一个自定义的缓存监听器并实现ServletContextListener接口, 并且在此自定义监听器中需要用到Spring的依赖注入功 ...
- Silverlight 创建 ImageButton
这几天一直在折腾怎么在silverlight 按钮上添加图片,直接向imagebutton那样设置成属性可以直接更改,最后到处查找资料终于搞出一个imagebutton了. <Style x:K ...
- (转)Linux: dirname、basename命令详解
Linux: dirname.basename命令详解 原文:http://blog.sina.com.cn/s/blog_3f63916f010143vo.html 一.dirname指令 1.功能 ...
- jquery字符串数组转json字符串 C#json字符串转字符串list
一.jquery字符串数组转json字符串 var str=['1','2','3']; var jsonText= JSON.stringify(str);//把一个对象转换成json字符串 str ...