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 贪吃的九头龙
[问题描述]传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落.有一 ...
随机推荐
- web.xml中的contextConfigLocation的作用
在web.xml中通过contextConfigLocation配置spring,contextConfigLocation 参数定义了要装入的 Spring 配置文件. 如果想装入多个配置文件,可以 ...
- [MCM]2014年美赛MCM题目原文及翻译
PROBLEM A: The Keep-Right-Except-To-Pass Rule In countries where driving automobiles on the right is ...
- 长沙Uber优步司机奖励政策(1月25日~1月31日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 深入浅出node(4) 异步编程
一)函数式编程基础 二)异步编程的优势和难点 2.1 优势 2.2 难点 2.2.1 异常处理 2.2.2 函数嵌套过深 2.2.3 阻塞 2.2.4 多线程编程 2.2.5 异步转同步 三)异步编程 ...
- ODBC 中遇到的错误
直接贴解决办法的链接: http://zhidao.baidu.com/link?url=pyd2AiazzsZr4IlMpiCdXlLC6nnao908xmqmY9QI0yj8vIGCbRPRrqh ...
- iOS开发总结-图片左右滑动浏览
// // PicViewController.m // BJ // // Created by shirenfeng on 16/9/13. // Copyright © 2016年 com.zyb ...
- 使用 maven:archetype 创建JSF2 + EJB3.1 + JPA2项目骨架并在JBoss WildFly 8.1上部署
运行下面命令创建项目骨架: mvn archetype:generate -DarchetypeGroupId=org.jboss.spec.archetypes -DarchetypeArtifac ...
- 数据存储(一)--SharedPreferences之你不知道的事
一.SharedPreferences将数据文件保存在指定路径上 SharedPreferences原则上是仅仅能保存在当前应用程序私有的shared_prefs文件夹中,只是也不是绝对的,我们能够用 ...
- spring mvc DispatcherServlet详解之三---request通过ModelAndView中获取View实例的过程
整个spring mvc的架构如下图所示: 上篇文件讲解了DispatcherServlet第二步:通过request从Controller获取ModelAndView.现在来讲解第三步:reques ...
- iOS--日历事件的获取和添加
日历添加事件 EKEventStore* eventStore = [[EKEventStore alloc] init];//获取日历类 EKEvent *event = [EKEvent even ...