Leyni, 罗莉 与 游乐场 | ||||||
| ||||||
Description | ||||||
Leyni喜欢和罗莉们玩,他认识n个罗莉,这些罗莉喜欢去游乐场玩,Leyni正在计划为她们建立一些游乐场,进而让每一个人都能去游乐场玩。 这些罗莉都分布在不同的城市,而且这些城市中,任意两个城市间有且只有一种路线(这个路线可能需要经过若干条城市之间的公路),每条城市之间的公路的长度都相等(都是1单位长度)。 现在这些城市都没有游乐场,Leyni要选择某些城市来建立游乐场,但是建立一个游乐场将花费k元。这样,对于有游乐场的城市中的罗莉将能不支付任何费用去游乐场玩;对于不建立游乐场的城市中的罗莉,Leyni将安排她去一个有游乐场的城市,并替她支付路费dlen元(其中len为该罗莉所在城市到指定城市的距离) Leyni想知道,为了让每个罗莉都能去游乐场玩,他最少要花费多少元? | ||||||
Input | ||||||
本题有多组测试数据,输入的第一行是一个整数T代表着测试数据的数量,接下来是T组测试数据。 对于每组测试数据: 第1行 包含两个整数n和k (1 ≤ n ≤ 200, 1 ≤ k ≤ 105)。 第2行 包含n – 1个整数di,下标从1开始 (di ≤ di + 1, 0 ≤ di ≤ 105)。 接下来n – 1行 每行包含了一对整数u和v,表示城市u和城市v之间存在一条公路(城市的下标从1开始)。 | ||||||
Output | ||||||
对于每组测试数据: 第1行 输出Leyni所需要的最小花费。 | ||||||
Sample Input | ||||||
1 8 10 2 5 9 11 15 19 20 1 4 1 3 1 7 4 6 2 8 2 3 3 5 | ||||||
Sample Output | ||||||
38 | ||||||
Hint | ||||||
对于样例,可以选择在城市3和城市4建立两个游乐场,并安排城市1、2、5、7、8的罗莉去城市3玩,安排城市6的罗莉去城市4玩。 | ||||||
Source | ||||||
哈理工2012春季校赛热身赛 2012.04.03 | ||||||
Author | ||||||
齐达拉图@HRBUST |
思路:
1、首先我们O(n^2)的去预处理出树上两点间距离。
2、因为涉及到最小花费,而且保证图是一棵树,那么我们肯定要想树型dp.
我们设定Dp【i】【 j】表示城市i的萝莉都到城市j去玩的最小花费。
那么不难推出其状态转移方程:Dp【u】【i】= d【dist[u][i]】+Σmin(Dp【v】【i】,min(Dp[v][j])+K);
3、那么在树上进行dp的过程维护一下即可。
其实这个问题还可以进行一波优化,大体的思路就是将状态转移方程改为:Dp【u】【i】= d【dist[u][i]】+Σmin(Dp【v】【i】,opt【i】+K);
这里opt【i】其实就是min(Dp【v】【j】)的最小值的点的编号。
所以这波可以优化一下。
没优化暴力去Dp的话是800+ms.优化之后是30+ms.........................
Ac代码(没优化的800+ms):
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
vector<int >mp[5000];
int dist[300][300];
int dp[300][300];
int d[5000];
int n,kk;
void dfs(int ss,int u,int from,int depth)
{
dist[ss][u]=depth;
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i];
if(v==from)continue;
else
{
dfs(ss,v,u,depth+1);
}
}
}
int Dfs(int u,int from)
{
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i];
if(v==from)continue;
Dfs(v,u);
}
for(int i=1;i<=n;i++)
{
dp[u][i]=d[dist[u][i]];
for(int j=0;j<mp[u].size();j++)
{
int minn=0x3f3f3f3f;
int v=mp[u][j];
for(int k=1;k<=n;k++)
{
minn=min(dp[v][k],minn);
}
dp[u][i]+=min(dp[v][i],minn+kk);
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&kk);
memset(dp,0,sizeof(dp));
memset(dist,0,sizeof(dist));
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++)mp[i].clear();
for(int i=1;i<=n-1;i++)
{
scanf("%d",&d[i]);
}
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
for(int i=1;i<=n;i++)dfs(i,i,-1,0);
Dfs(1,-1);
int output=0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
output=min(dp[1][i]+kk,output);
}
printf("%d\n",output);
}
}
Ac代码2(优化之后的32ms):
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
vector<int >mp[5000];
int dist[300][300];
int dp[300][300];
int opt[300];
int d[5000];
int n,kk;
void dfs(int ss,int u,int from,int depth)
{
dist[ss][u]=depth;
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i];
if(v==from)continue;
else
{
dfs(ss,v,u,depth+1);
}
}
}
void Dfs(int u,int from)
{
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i];
if(v==from)continue;
Dfs(v,u);
}
int tmp=0x3f3f3f3f;
for(int i=1;i<=n;i++)
{
dp[u][i]=d[dist[u][i]];
for(int j=0;j<mp[u].size();j++)
{
int v=mp[u][j];
if(opt[v])
{
dp[u][i]+=min(dp[v][i],dp[v][opt[v]]+kk);
}
}
if(dp[u][i]<tmp)
{
opt[u]=i;
tmp=dp[u][i];
}
}
return ;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&kk);
memset(opt,0,sizeof(opt));
memset(dist,0,sizeof(dist));
memset(d,0,sizeof(d));
for(int i=1;i<=n;i++)mp[i].clear();
for(int i=1;i<=n-1;i++)
{
scanf("%d",&d[i]);
}
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
for(int i=1;i<=n;i++)dfs(i,i,-1,0);
Dfs(1,-1);
printf("%d\n",dp[1][opt[1]]+kk);
}
}