您的位置:首页 > 其它

贪吃的九头龙-----树形dp

2013-05-21 20:52 204 查看
开始切树形dp。。。

思路:

经研究发现,当m大于3的时候,可以把m当成3来运算。

先把多叉树转化成二叉树,方便寻找每个节点的儿子和兄弟。

dp[i][j][k]: 以i节点为根节点的子树,有j个大头,节点i的状态为k,这时候的难受值。(k=0,1)当k=0时,代表小头吃这个节点,反之,大头吃。

map[i][j]: 节点i到节点j的边长。

dp[x][j][1]=min(dp[x][j][1],dp[y][k][1]+tmp[j-k][1]+map[x][y],dp[y][k][0]+tmp[j-k][1]);

dp[x][j][0]=min(dp[x][j][0],dp[y][k][0]+tmp[j-k][0]+t ,dp[y][k][1]+tmp[j-k][0]);

tmp[i][j]: 在运算一个节点之前,已经运算过的节点形成的dp[x][i][j];

t代表当一条边两边都是0时,所应该增加的难受值。

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
struct list
{
int l;
int r;
}node[1001];
int n,m,need;
int map[301][301];
int min3(int a,int b,int c)
{
if(a>b)a=b;
if(a>c)a=c;
return a;
}
void init()
{
int i,a,b,c;
cin>>n>>m>>need;
for(i=1;i<=n;i++)
{
node[i].l=node[i].r=0;
}
for(i=0;i<n-1;i++)
{
cin>>a>>b>>c;
if(a>b)swap(a,b);
map[a][b]=c;
if(node[a].l==0)
{
node[a].l=b;
}
else
{
a=node[a].l;
while(node[a].r)
{
a=node[a].r;
}
node[a].r=b;
}
}
}
int sum[301];
int dp[301][301][10];
int tmp[301][10];
void dfs(int x)
{
dp[x][1][1]=0;
dp[x][0][0]=0;
int j,k;
sum[x]=1;
int i;
i=node[x].l;
while(i)
{
int y=i;
dfs(y);
int t;
t=0;
if(m==2)t=map[x][y];
sum[x]+=sum[y];
for(j=0;j<301;j++)
{
tmp[j][0]=dp[x][j][0];
tmp[j][1]=dp[x][j][1];
}
memset(dp[x],0x2f,sizeof(dp[x]));
for(j=sum[x];j>=0;j--)
{
for(k=j-1;k>=0;k--)dp[x][j][1]=min3(dp[x][j][1],dp[y][k][0]+tmp[j-k][1],dp[y][k][1]+tmp[j-k][1]+map[x][y]);
for(k=j;k>=0;k--) dp[x][j][0]=min3(dp[x][j][0],dp[y][k][1]+tmp[j-k][0],dp[y][k][0]+tmp[j-k][0]+t);
}
i=node[i].r;
}
}
int main()
{
init();
if(n<m+need-1)
{
printf("-1\n");
return 0;
}
memset(dp,0x2f,sizeof(dp));
dfs(1);
cout<<dp[1][need][1];
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: