Vijos1523 NOI2002 贪吃的九头龙 树形dp
思路不算很难,但细节处理很麻烦
前面建图、多叉转二叉,以及确定dp处理序列的过程都是套路,dp的状态转移过程以注释的形式阐述
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
int N,M,K;
struct Edge
{
int to,next;
int weight;
void assign(int t,int n,int w)
{
to=t; next=n; weight=w;
}
};
Edge elist[];
];
];
][]; //0 is left and 1 is right
];
int ecnt;
void initE()
{
memset(head,-,sizeof(head));
memset(vis,,sizeof(vis));
memset(child,-,sizeof(child));
weight[]=;
ecnt=;
}
inline void addEdge(int from,int to,int weight)
{
elist[ecnt].assign(to,head[from],weight);
head[from]=ecnt++;
elist[ecnt].assign(from,head[to],weight);
head[to]=ecnt++;
}
bool input()
{
scanf("%d%d%d",&N,&M,&K);
bool ok=true;
>N) ok=false; //输出-1的情况
initE();
int a,b,c;
;i<N;i++)
{
scanf("%d%d%d",&a,&b,&c);
addEdge(a,b,c);
}
return ok;
}
void buildBinaryTree(int cur)
{
vis[cur]=true;
;
;e=elist[e].next)
{
int& to=elist[e].to;
int& w=elist[e].weight;
if(!vis[to])
{
weight[to]=w;
)
child[cur][]=to;
else
child[last][]=to;
last=to;
buildBinaryTree(to);
}
}
}
][][];
/*
dp[n][m][k]:处理到第n个节点时,大头已经吃掉了m个果子,其父节点将被(k=1)或不被(k=0)大头吃,此情况下的最优值
dp[n]的处理范围:孩子兄弟二叉树中,以节点n为根的子树
dp的初值见下方代码,ans=dp[v][K-1][1],v为孩子兄弟二叉树中1号节点的左孩子
*/
std::queue<int> seq;
void getSeq(int cur)
{
]!=-) getSeq(child[cur][]);
]!=-) getSeq(child[cur][]);
seq.push(cur);
} //先处理右孩子,再处理左孩子,最后处理自身
/*
M>=3时,小头的总难受值的最小值必为0
取两个小头A和B,奇数层的果子由A吃,偶数层的果子由B吃,这样难受值必为0
所以只需考虑大头的难受值
*/
int solve_aux_3()
//若无特殊说明:solve_aux函数注释中提到的有关树的概念均指孩子兄弟二叉树,opt代指当前决策的较优值,“不吃”和“吃”均指大头
{
int ans;
while(!seq.empty())
{
int cur=seq.front();
seq.pop();
);
]!=-) st|=;
]!=-) st|=;
) //cur是叶子节点
{
dp[cur][][]=dp[cur][][]=;
dp[cur][][]=;
dp[cur][][]=weight[cur];
}
) //只有右孩子,状态转移和线性dp类似
{
];
dp[cur][][]=;
;i<K;i++)
dp[cur][i][]=std::min(dp[rc][i][],dp[rc][i-][]); //对于当前果子,opt=min(不吃,吃)
dp[cur][][]=;
;i<K;i++)
dp[cur][i][]=std::min(dp[rc][i][],dp[rc][i-][]+weight[cur]); //opt=min(不吃,吃)
}
) //只有左孩子
{
];
) ans=dp[lc][K-][]; //最终答案
else
{
dp[cur][][]=dp[cur][][]=;
;i<K;i++)
dp[cur][i][]=std::min(dp[lc][i][],dp[lc][i-][]); //opt=min(不吃,吃)
;i<K;i++)
dp[cur][i][]=std::min(dp[lc][i][],dp[lc][i-][]+weight[cur]); //opt=min(不吃,吃)
}
}
else //st=3,既有左孩子又有右孩子,最复杂的情况
{
];
];
dp[cur][][]=dp[cur][][]=;
;i<K;i++) //dp[cur][i][0]
{
;j<=i;j++) //不吃当前的果子
dp[cur][i][]=std::min(dp[lc][j][]+dp[rc][i-j][],dp[cur][i][]); //分配i,取最优的分配方案
;j<i;j++) //吃当前的果子
dp[cur][i][]=std::min(dp[lc][j][]+dp[rc][i-j-][],dp[cur][i][]);
}
;i<K;i++) //dp[cur][i][1]
{
;j<=i;j++) //不吃
dp[cur][i][]=std::min(dp[cur][i][],dp[lc][j][]+dp[rc][i-j][]);
;j<i;j++) //吃
dp[cur][i][]=std::min(dp[cur][i][],dp[lc][j][]+dp[rc][i-j-][]+weight[cur]);
}
}
}
return ans;
}
/*
M=2时的dp方程与M>2时形式类似,但细节上有所不同(包括初值的设置和状态转移)
此时大头和小头的难受值必须同时考虑
*/
int solve_aux_2()
{
int ans;
while(!seq.empty())
{
int cur=seq.front();
seq.pop();
);
]!=-) st|=;
]!=-) st|=;
)
{
dp[cur][][]=dp[cur][][]=;
dp[cur][][]=dp[cur][][]=weight[cur]; //注意这里赋初值的差异
//dp[cur][0][0]表示原树中当前节点和父节点的果子都由小头吃,所以该段树枝的难受值也必须考虑
//类似的差异会在下方用“!”标注,请读者自行体会
}
)
{
];
dp[cur][][]=dp[rc][][];
dp[cur][][]=dp[rc][][]+weight[cur]; //!
;i<K;i++)
{
dp[cur][i][]=std::min(dp[rc][i][]+weight[cur],dp[rc][i-][]); //!
dp[cur][i][]=std::min(dp[rc][i][],dp[rc][i-][]+weight[cur]);
}
}
)
{
];
) ans=dp[lc][K-][];
else
{
dp[cur][][]=dp[lc][][]; //!
dp[cur][][]=dp[lc][][]+weight[cur];
;i<K;i++)
{
dp[cur][i][]=std::min(dp[lc][i][]+weight[cur],dp[lc][i-][]); //!
dp[cur][i][]=std::min(dp[lc][i][],dp[lc][i-][]+weight[cur]);
}
}
}
else
{
];
];
dp[cur][][]=dp[lc][][]+dp[rc][][]; //!
dp[cur][][]=dp[lc][][]+dp[rc][][]+weight[cur];
;i<K;i++)
{
;j<=i;j++)
dp[cur][i][]=std::min(dp[cur][i][],dp[lc][j][]+dp[rc][i-j][]+weight[cur]); //!
;j<i;j++)
dp[cur][i][]=std::min(dp[cur][i][],dp[lc][j][]+dp[rc][i-j-][]);
;j<=i;j++)
dp[cur][i][]=std::min(dp[cur][i][],dp[lc][j][]+dp[rc][i-j][]);
;j<i;j++)
dp[cur][i][]=std::min(dp[cur][i][],dp[lc][j][]+dp[rc][i-j-][]+weight[cur]);
}
}
}
return ans;
}
int solve()
{
memset(dp,0x3f,sizeof(dp));
buildBinaryTree();
getSeq();
?solve_aux_2():solve_aux_3();
}
int main()
{
if(!input()) printf("-1");
else printf("%d",solve());
;
}
Vijos1523 NOI2002 贪吃的九头龙 树形dp的更多相关文章
- [NOI2002]贪吃的九头龙(树形dp)
[NOI2002]贪吃的九头龙 题目背景 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是 说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的 ...
- [codevs1746][NOI2002]贪吃的九头龙
[codevs1746][NOI2002]贪吃的九头龙 试题描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时 ...
- vojis1523 NOI2002 贪吃的九头龙
描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落. 有一天, ...
- [NOI2002] 贪吃的九头龙
题目类型:树形DP 传送门:>Here< 题意:有一只九头龙要吃了一颗树,给出一棵\(N\)个节点的带边权的树.九头龙有\(M\)个头,其中一个是大头,大头要吃恰好\(K\)个节点,其他头 ...
- 洛谷 P4362 [NOI2002]贪吃的九头龙
https://www.luogu.org/problemnew/show/P4362 首先有个很显然的dp:ans[i][j][k]表示i节点用j号头,i节点为根的子树中共有k个点用大头时i节点为根 ...
- Vijos1523贪吃的九头龙【树形DP】
贪吃的九头龙 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头 ...
- Vijos 1523 贪吃的九头龙 【树形DP】
贪吃的九头龙 背景 安徽省芜湖市第二十七中学测试题 NOI 2002 贪吃的九头龙(dragon) Description:OfficialData:OfficialProgram:Converted ...
- 贪吃的九头龙(tyvj P1523)
T2 .tyvj P1523贪吃的九头龙 描述 传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于 ...
- codevs1746 贪吃的九头龙
[问题描述]传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落.有一 ...
随机推荐
- Microsoft Internet Explorer 内存破坏漏洞(CVE-2013-3193)(MS13-059)
漏洞版本: Microsoft Internet Explorer 6 - 10 漏洞描述: BUGTRAQ ID: 61678 CVE(CAN) ID: CVE-2013-3193 Windows ...
- CXF Service Interceptor请求,响应报文之控制台输出
一:定义接口 @WebService(targetNamespace = "http://www.unionpay.com/client/appprovider", name = ...
- C++获取本机IP地址
对网络库简单的封装了一下,以后自己使用的时候方便了很多 #include <WinSock2.h> #pragma comment(lib,"ws2_32") //链接 ...
- bzoj 2463 [中山市选2009]谁能赢呢?(博弈)
2463: [中山市选2009]谁能赢呢? Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1290 Solved: 944[Submit][Stat ...
- vijosP1046 观光旅游(最小环)
vijosP1046 观光旅游 链接:https://vijos.org/p/1046 [思路] Floyd求解最小环. [代码] #include<iostream> using nam ...
- Automake
Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...
- [CSS]利用伪元素实现一些特殊图形
给定的html代码是: <div class='square'></div> 平常实现我们常是通过添加小的icon来实现,不仅需要添加图片资源,还需要改动html结构. CSS ...
- CMS收集器
CMS收集周期 CMS并非没有暂停,而是用两次短暂停来替代串行标记整理算法的长暂停,它的收集周期是这样:初始标记(CMS-initial-mark) -> 并发标记(CMS-concurrent ...
- 访问者模式(Visitor)
@@@模式定义: 表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下 定义作用于这些元素的新操作. @@@练习示例: 扩展客户管理的功能 @@@示例代码: \patter ...
- 08_android入门_android-async-http开源项目介绍及用法
android-async-http开源项目可以是我们轻松的获取网络数据或者向server发送数据.使用起来很easy,关于android-async-http开源项目的介绍内容来自于官方:http: ...