您的位置:首页 > 其它

HDU 5148 Cities 树形DP(背包)

2017-10-07 15:20 405 查看
HDU 5148

题意;n个点的树,第i条边长度为c[i],任意选中k个点为特殊点,这k个点中,任意两点间距离的期望值最小为多少?

n<=2000,k<=min(50,n) c[i]<=1e6.

k个点任意选两个有k^2种选法 (u,v)对期望贡献为 dis(u,v)/k^2 也就是说要求这min(k个点中任意两点距离累加和/k^2)

先考虑一个特殊的情况 当k==n时 树上任意两点距离的累加和.

若u的子树中,有x个节点被选中,则(u,v)边贡献为x*(k-x) (u下面每个节点都往u上方走k-x次)

设dp[u][x] 从u中选x个结点时,该子树对答案的贡献值最小为?

枚举子树u的子树v选多少个就好
dp[u][x]= min(dp[u][x], dp[u][x-y]+dp[v][y]+cost(u,v)*y*(k-y)*2ll).

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,ll> ii;
const int N=4e3+20;
const ll inf=2e17;
vector<ii> e
;
int n,k;
ll dp
[51];
void dfs(int u,int fa)
{
dp[u][0]=dp[u][1]=0;
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i].first;
ll w=e[u][i].second;
if(v==fa)
continue;
dfs(v,u);
b919
for(int y=k;y>=0;y--)
{
for(int x=0;x<=y;x++)
dp[u][y]=min(dp[u][y],dp[u][y-x]+dp[v][x]+w*x*(k-x)*2ll);
}
}

}
int main()
{
int T,n,u,v;
ll w;
cin>>T;
while(T--)
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
e[i].clear();
for(int i=1;i<=n-1;i++)
{
scanf("%d%d%lld",&u,&v,&w);
e[u].push_back(ii(v,w));
e[v].push_back(ii(u,w));
}
for(int i=1;i<=n;i++)
for(int j=2;j<=n;j++)
dp[i][j]=inf;
dfs(1,-1);
cout<<dp[1][k]<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: