您的位置:首页 > 其它

BZOJ 1812 Ioi2005 riv 树形dp

2016-07-23 17:25 295 查看
题目大意:给定一棵树,每个点有权值,每条边有边权(单向边)。你可以选取K个黑点,使得从每个点移动到距离他最近的黑点的花费(距离*点权)的总和最小。

题目分析:先将该树转化成二叉树方便动态规划。由于当前节点i的子树的花费与最近的黑点j有关系。且要记录下当前已经用过几个黑点。所以f[i][j][k]表示当前这棵子树的根节点为i,最近的黑点为j,用了k个黑点的花费。
记忆化搜索方便实现。
考虑转移:对于当前这个节点i可以选取它作为黑点,也可不选。  

所以 


极限时间复杂度O(n²k²),事实上应该远小于这个上界。 

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#include<cmath>
#include<cctype>
#include<cassert>
#include<climits>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define RepD(i,n) for(int i=n;i>=0;i--)
#define MEM(a) memset(a,0,sizeof(a))
#define MEMI(a) memset(a,127,sizeof(a))
#define MEMi(a) memset(a,128,sizeof(a))
#define INF (2139062143)
#define phiF (1000000006)
#define MAXN (1000000+10)
typedef long long LL;
struct info{
int fa,d,w,l,r;
}a[205];

int dis[205],tree[205],f[105][55][105],m,n,x;

void dfs(int u){
if (u<0) return;
dis[u]=dis[a[u].fa]+a[u].d;
dfs(a[u].l);
dfs(a[u].r);
}

int dp(int i,int j,int k){
if (f[i][j][k]<0){
f[i][j][k]=INF;
Fork (ii,0,j){
int	t=(dis[i]-dis[k])*a[i].w;
if (a[i].l!=-1) t+=dp(a[i].l,ii,k);
if (a[i].r!=-1) t+=dp(a[i].r,j-ii,k);
f[i][j][k]=min(f[i][j][k],t);
if (ii<j) {
t=0;
if (a[i].l!=-1) t+=dp(a[i].l,ii,i);
if (a[i].r!=-1) t+=dp(a[i].r,j-ii-1,k);
f[i][j][k]=min(f[i][j][k],t);
}
}

}
return f[i][j][k];
}

int main(){
scanf("%d%d",&n,&m);
Fork (i,0,101) a[i].l=a[i].r=-1;
For (i,n){
scanf("%d%d%d",&a[i].w,&x,&a[i].d);
if (a[x].l==-1) a[x].l=i;else a[tree[x]].r=i;
a[i].fa=x;
tree[x]=i;
}

dfs(0);
MEMi(f);
printf("%d",dp(0,m,0));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  树形dp bzoj Ioi