ACM: 动态规划题 黑书-…
2016-05-19 23:26
274 查看
贪吃的九头蛇
【问题描述】传说中的九头龙是一种特别贪吃的动物。虽然名字叫“九头龙”,但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头因衰老而自己脱落。
有一天,有M个脑袋的九头龙看到一棵长有N个果子的果树,喜出望外,恨不得一口把它全部吃掉。可是必须照顾到每个头,因此它需要把N个果子分成M组,每组至少有一个果子,让每个头吃一组。
这M个脑袋中有一个最大,称为“大头”,是众头之首,它要吃掉恰好K个果子,而且K个果子中理所当然地应该包括唯一的一个最大的果子。果子由N-1根树枝连接起来,由于果树是一个整体,因此可以从任意一个果子出发沿着树枝“走到”任何一个其他的果子。
对于每段树枝,如果它所连接的两个果子需要由不同的头来吃掉,那么两个头会共同把树枝弄断而把果子分开;如果这两个果子是由同一个头来吃掉,那么这个头会懒得把它弄断而直接把果子连同树枝一起吃掉。当然,吃树枝并不是很舒服的,因此每段树枝都有一个吃下去的“难受值”,而九头龙的难受值就是所有头吃掉的树枝的“难受值”之和。
九头龙希望它的“难受值”尽量小,你能帮它算算吗?
例如图1所示的例子中,果树包含8个果子,7段树枝,各段树枝的“难受值”标记在了树枝的旁边。九头龙有两个脑袋,大头需要吃掉4个果子,其中必须包含最大的果子。即N=8,M=2,K=4:
图一描述了果树的形态,图二描述了最优策略。
【输入文件】
输入文件dragon.in的第1行包含三个整数N
(1<=N<=300),M
(2<=M<=N),K
(1<=K<=N)。
N个果子依次编号1,2,...,N,且最大的果子的编号总是1。第2行到第N行描述了果树的形态,每行包含三个整数a
(1<=a<=N),b
(1<=b<=N),c
(0<=c<=105),表示存在一段难受值为c的树枝连接果子a和果子b。
【输出文件】
输出文件dragon.out仅有一行,包含一个整数,表示在满足“大头”的要求的前提下,九头龙的难受值的最小值。如果无法满足要求,输出-1。
【样例输入】
8 2 4
1 2 20
1 3 4
1 4 13
2 5 10
2 6 12
3 7 15
3 8 5
8 3 4
1 2 20
1 3 4
1 4 13
2 5 10
2 6 12
3 7 15
3 8 5
2 2 1
1 2 10
2 2 2
1 2 10
【样例输出】
4
0
0
-1
题意: 一条九头龙的动物, 有M个脑袋, 每个脑袋都必须吃到果子, 一棵有N个果子的树, 分配给它每个头吃,
其中一个最大的头要吃K个果子,
其余分配给其它的头, 如果一个头同时吃到相邻的果子会有一个难受
值,
现在要你分配果子使得难受值的和最小.
解题思路: (黑书思路)
1. 无解情况, 果子不够吃, N<K+M-1
2. 当M=2时, 大头要不吃到相邻的要不吃不到. 当M>=3时, 确定大头吃掉之后,
剩下的果子按照果树
高度奇偶分配即可. 可以确定问题: 当M=2时, 难受值=两端果子被大头或小头吃的难受值之和.
当M>=3时, 两端的果子都被大头吃掉的难受值之和.(因为问题有解,
所以剩下一定满足不相邻分配)
3. 为了简化问题(减少决策), 将多叉树转化成二叉树结构(左孩子右兄弟结构).
设状态: dp[i][j][k]: 表示以i节点为根的子树有j个果子分配给大头吃的最小难受值. 其中,
k=0表示fa[i]被大头吃, k=1表示fa[i]被小头吃.
方程: dp[i][j][k] = min(
dp[X1][j1][1]+dp[X2][j-j1][k]
+ judge(k,1)*cost(i, fa[i]);
dp[X1][j1][0]+dp[X2][j-j1-1][k] + judge(k,0)*cost(i, fa[i]);
);
X1:是i节点的字节点,
X2:是i节点的兄弟节点(父亲被吃情况相同时k); judge判断k与1是否相同.
judge(k1,
k2): (k1 == 1&&k2 ==
1 ==> judge(k1,k2) = 1)
(k1
== 0&&k2 ==
0&&M==2 ==>
judge(k1, k2) == 1)
other
judge(k1, k2) == 0;
边界:
dp(0,0,k) = 0; dp(0,j,k) = INF(无穷大, 表示情况不成立,
j>0);
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
#define MAX 305
const int INF = (1<<29);
struct node
{
int v;
int
next;
}edges[MAX*2];
int n, m, K;
int dp[MAX][MAX][2];
int fa[MAX], son[MAX], bro[MAX], ch[MAX];
int first[MAX], num;
int cost[MAX][MAX];
inline int min(int a, int b)
{
return a
< b ? a : b;
}
inline void add(int u, int v)
{
edges[num].v
= v;
edges[num].next = first[u];
first[u] =
num++;
}
void readGraph()
{
memset(dp,
-1, sizeof(dp));
memset(first, -1, sizeof(first));
memset(son,
0, sizeof(son));
memset(bro,
0, sizeof(bro));
memset(cost,
0, sizeof(cost));
num =
0;
for(int i =
1; i <= n; ++i)
{
ch[i] =
1;
fa[i] =
i;
}
int u, v,
w;
for(int i =
1; i < n; ++i)
{
scanf("%d %d
%d", &u, &v,
&w);
cost[u][v] =
cost[v][u] = w;
add(u,
v);
add(v,
u);
}
}
void makeGraph(int u, int f) //转换成二叉树
{
fa[u] =
f;
int *point =
&son[u];
for(int e =
first[u]; e != -1; e = edges[e].next)
{
int v =
edges[e].v;
if(v == f)
continue;
*point =
v;
point =
&bro[v];
makeGraph(v,
u);
}
}
inline int judge(int i, int j)
{
if(i == 1
&& j == 1) return 1;
else if(i ==
0 && j == 0
&& m == 2) return 1;
else return
0;
}
int dfs(int x)
{
if( !son[x]
&& !bro[x] ) return ch[x];
return ch[x]
+= dfs(son[x])+dfs(bro[x]);
}
int DP(int i, int j, int k)
{
if(j
< 0) return INF;
if(dp[i][j][k] != -1) return dp[i][j][k];
if(j
> ch[i]) return dp[i][j][k] = INF;
if(i == 0
&& j == 0) return dp[i][j][k] =
0;
if(i == 0)
return dp[i][j][k] = INF;
int ans =
INF;
int temp1 =
INF, temp2 = INF;
for(int t =
0; t <= j; ++t)
{
temp1 =
DP(son[i], t, 1)+DP(bro[i], j-t, k)+judge(k,1)*cost[i][fa[i]];
//小头吃i
temp2 =
DP(son[i], t, 0)+DP(bro[i], j-t-1, k)+judge(k,0)*cost[i][fa[i]];
//大头吃i
ans =
min(ans, min(temp1, temp2));
}
return
dp[i][j][k] = ans;
}
int main()
{
freopen("input.txt", "r", stdin);
while(scanf("%d %d %d", &n, &m,
&K) != EOF)
{
readGraph();
makeGraph(1,
1);
dfs(1);
if(n
< K+m-1) printf("-1\n");
相关文章推荐
- ACM: 计算几何题 poj 2066
- ACM: 动态规划题 poj&nb…
- ACM: 华东师范oj 1600&n…
- ACM: 金华赛区题目 水题…
- ACM: 动态规划题 poj&nb…
- ACM: 动态规划题 《黑书…
- ACM: 动态规划题 sicily…
- ACM: 图论题 poj 1…
- ACM: 图论题 poj 1466 最大独立团
- ACM: 图论题 poj 1…
- 图论: 差分约束系统
- ACM: 图论题 poj 1275 差分约束题
- ACM: 图论题 poj 1236 强连通
- ACM: 图论题 poj 1149 网络流问题
- ACM: 图论题 poj 1201 差分约束
- ACM: 搜索题 poj 1020
- ACM: 图论题 poj 3308 最大流问题
- Android的自定义控件起步
- ACM: 图论题 poj 3177 同 3352
- dos批处理中%~dp0%的说明