码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ4711 小奇挖矿

时间:2018-03-26 20:44:47      阅读:144      评论:0      收藏:0      [点我收藏+]

标签:cin   name   方案   计算   tar   blog   双向   swa   namespace   

Description

【题目背景】
小奇在喵星系使用了无限非概率驱动的采矿机,以至于在所有星球上都采出了一些矿石,现在它准备建一些矿石仓
库并把矿石运到各个仓库里。
【问题描述】
喵星系有n个星球,标号为1到n,星球以及星球间的航线形成一棵树。所有星球间的双向航线的长度都为1。小奇要
在若干个星球建矿石仓库,设立每个仓库的费用为K。对于未设立矿石仓库的星球,设其到一个仓库的距离为i,则
将矿石运回的费用为Di。请你帮它决策最小化费用。

Input

第一行2个整数n,K。
第二行n-1个整数,D1,D2,…Dn-1,保证Di<=Di+1。
接下来n-1行,每行2个整数x,y,表示星球x和星球y存在双向航线。
n<=200,0<=K,Di<=100000

Output

输出一行一个整数,表示最小费用。

Sample Input

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
【样例解释】
在1,2号星球建立仓库。
令$f[i][j]$表示$i$的子树已经计算离$i$最近的仓库为$j$,且还没有算上建造的方案
一个儿子有2种情况;
1.最近的是k
2.最近的是j
写出来就是
$f[x][i]=min(f[v][j]+k,f[v][i])$
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cmath>
  6 using namespace std;
  7 struct Node
  8 {
  9   int next,to;
 10 }edge[200001];
 11 int num,head[21],cnt,tot,q[21],p[21],dep[21],fa[21],size[21],son[21],top[21];
 12 int dfn[21],n,k,d[21],ans,Min,sum,f[201][201],dis[201][201];
 13 void add(int u,int v)
 14 {
 15   num++;
 16   edge[num].next=head[u];
 17   head[u]=num;
 18   edge[num].to=v;
 19 }
 20 void dfs1(int x,int pa)
 21 {int i;
 22   dep[x]=dep[pa]+1;
 23   fa[x]=pa;
 24   size[x]=1;
 25   for (i=head[x];i;i=edge[i].next)
 26     {
 27       int v=edge[i].to;
 28       if (v==pa) continue;
 29       dfs1(v,x);
 30       size[x]+=size[v]; 
 31       if (size[v]>size[son[x]]) son[x]=v;
 32     } 
 33 }
 34 void dfs2(int x,int pa,int tp)
 35 {int i;
 36   top[x]=tp;
 37   dfn[x]=++tot;
 38   if (son[x]) dfs2(son[x],x,tp);
 39   for (i=head[x];i;i=edge[i].next)
 40     {
 41       int v=edge[i].to;
 42       if (v==pa||son[x]==v) continue;
 43       dfs2(v,x,v);
 44     }
 45 }
 46 int lca(int x,int y)
 47 {
 48   int as=0;
 49   while (top[x]!=top[y])
 50     {
 51       if (dep[top[x]]<dep[top[y]]) swap(x,y);
 52       x=fa[top[x]];
 53     }
 54   if (dep[x]>dep[y]) swap(x,y);
 55   return x;
 56 }
 57 int get_dis(int x,int y)
 58 {
 59   return dep[x]+dep[y]-2*dep[lca(x,y)];
 60 }
 61 void dfs(int x,int pa)
 62 {int i,j;
 63   for (i=1;i<=n;i++)
 64     f[x][i]=d[dis[x][i]];
 65   for (i=head[x];i;i=edge[i].next)
 66     {
 67       int v=edge[i].to;
 68       if (v==pa) continue;
 69       dfs(v,x);
 70       int as=2e9;
 71       for (j=1;j<=n;j++)
 72     as=min(as,f[v][j]+k);
 73       for (j=1;j<=n;j++)
 74     f[x][j]+=min(as,f[v][j]);
 75     }
 76 }
 77 int main()
 78 {int i,u,v,j;
 79   cin>>n>>k;
 80   for (i=1;i<=n-1;i++)
 81     {
 82       scanf("%d",&d[i]);
 83     }
 84   for (i=1;i<=n-1;i++)
 85     {
 86       scanf("%d%d",&u,&v);
 87       add(u,v);add(v,u);
 88     }
 89   dfs1(1,0);
 90   dfs2(1,0,1);
 91   for (i=1;i<=n;i++)
 92     {
 93       for (j=1;j<=n;j++)
 94     {
 95       dis[i][j]=get_dis(i,j);
 96     }
 97     }
 98   dfs(1,0);
 99   ans=2e9;
100   for (i=1;i<=n;i++)
101     ans=min(ans,f[1][i]+k);
102   cout<<ans;
103 }

 

BZOJ4711 小奇挖矿

标签:cin   name   方案   计算   tar   blog   双向   swa   namespace   

原文地址:https://www.cnblogs.com/Y-E-T-I/p/8653194.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!