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 贪吃的九头龙
[问题描述]传说中的九头龙是一种特别贪吃的动物.虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落.有一 ...
随机推荐
- Research Papers
NSE, $\bbu$ [Papers]NSE, $u$, Lorentz space [Sohr, JEE, 2001] [Papers]NSE, $u$, Lorentz space [Bjorl ...
- [QT]构建正则表达式测试
正则表达式是个强大的东西 暂时先记录一个用法: QString str = "Peak memory: KEY s"; QString data = "Peak memo ...
- swfupload 在ie9以上浏览器报错问题记录
解决办法: swfuploadl.js line 840左右 SWFUpload.prototype.cleanUp if (typeof(movieElement[key]) === "f ...
- hdoj 1969 Pie【二分】
Pie Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...
- 如何解决 SogouIinput not enough space for thread data ?? 虚拟内存
问题:总是提示没有足够的空间读写数据 上图: 原因: 可能是虚拟内存设置了过大了[我不知道明白是不是也是这样,我出现这个问题就是因为我把虚拟内存设置成了4G,我的物理内存是2G的] 具体问题具体分析, ...
- C#截取指定字符串函数
本文转载:http://www.cnblogs.com/liufei88866/archive/2012/05/12/2497395.html 一.通过函数方式进行获取. public string ...
- Cubieboard 开箱和入门 | Name5566 分类: cubieboard 2014-11-08 17:27 251人阅读 评论(0) 收藏
Cubieboard 开箱和入门 2014 年 01 月 29 日 by name5566 Categories: Computer Science, Cubieboard Hello Cubiebo ...
- SQL Server未找到或无法訪问server问题解决
问题信息:"在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误.未找到或无法訪问服务器.请验证实例名称是否正确而且 SQL Server 已配置为同意远程连接. (pr ...
- 剑指offer: 38 数字在排序数组中出现的次数
题目描述 统计一个数字在排序数组中出现的次数.例如输入排序数组{1,2,3,3,3,3,4,5} 和数字3,输出4. 思路如下 1. 预估时间复杂度,最复杂情况是,顺序扫描,统计K出现的次数,时间复杂 ...
- vim 缩写abbreviation
创建 :ab abbreviation pharse 取消 :unab abbreviation 缩写使用 insert模式下输入缩写,Enter键获得pharse.