Hrbust 1329 Leyni, 罗莉 与 游乐场【树型Dp+思维】好题!

来源:互联网 发布:java 时间段 拆分 编辑:程序博客网 时间:2024/05/21 07:47

Leyni, 罗莉 与 游乐场Time Limit: 2000 MSMemory Limit: 65536 KTotal Submit: 55(16 users)Total Accepted: 20(13 users)Rating: Special Judge: NoDescription

Leyni喜欢和罗莉们玩,他认识n个罗莉,这些罗莉喜欢去游乐场玩,Leyni正在计划为她们建立一些游乐场,进而让每一个人都能去游乐场玩。

这些罗莉都分布在不同的城市,而且这些城市中,任意两个城市间有且只有一种路线(这个路线可能需要经过若干条城市之间的公路),每条城市之间的公路的长度都相等(都是1单位长度)。

现在这些城市都没有游乐场,Leyni要选择某些城市来建立游乐场,但是建立一个游乐场将花费k元。这样,对于有游乐场的城市中的罗莉将能不支付任何费用去游乐场玩;对于不建立游乐场的城市中的罗莉,Leyni将安排她去一个有游乐场的城市,并替她支付路费dlen元(其中len为该罗莉所在城市到指定城市的距离)

Leyni想知道,为了让每个罗莉都能去游乐场玩,他最少要花费多少元?

Input

本题有多组测试数据,输入的第一行是一个整数T代表着测试数据的数量,接下来是T组测试数据。

对于每组测试数据:

1 包含两个整数nk (1 ≤ n ≤ 200, 1 ≤ k ≤ 105)

2 包含n – 1个整数di,下标从1开始 (di ≤ di + 1, 0 ≤ di ≤ 105)

接下来n – 1 每行包含了一对整数uv,表示城市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建立两个游乐场,并安排城市12578的罗莉去城市3玩,安排城市6的罗莉去城市4玩。

Source哈理工2012春季校赛热身赛 2012.04.03Author齐达拉图@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);    }}




阅读全文
0 0
原创粉丝点击