访问计划

题目描述

一棵n个点有边权的树,现在要从根节点出发遍历每条边并返回根节点,沿路行走的花费为边权,此外可以使用不超过k次传送门,每次花费c元跳到任意一个节点。求最小花费。

1<=n,k<=2000,多组数据,∑n<=10000,答案在int范围内。

本题包含多组数据。
每组数据第一行三个整数 N , K , C 。
接下来 N 行,每行三个整数 u , v , w 表示一条连接 u 和 v 的道路,通
过这条道路的花费为 w

样例输入

3 1 1
0 1 1
0 2 1
3 1 3
0 1 1
1 2 1

样例输出

3
4

 

首先每条树边只会经过1或2次,这个似乎十分显然,证明可以用欧拉回路的判定来证。

 

而传送相当于是添加了一些能且仅能经过一次的边,那么每条边走过的奇偶性与该字数内新加顶点奇偶性相同,因为没有传送因为要来回必然是偶数,两个顶点都在子树内的传送对这条边没有意义,有一次传送就会是奇数。

 

所以(fa[x],x)这条边会经过2-(x子树内新加点个数)%2次。

 

那么我们只要记f[a][b]为a子树内有b个新加顶点的代价,直接树上背包转移即可。

 

最后显然用f[1][2*x]+x*c更新答案即可。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 typedef long long lol;
 8 struct Node
 9 {
10   int next,to;
11   lol dis;
12 }edge[4001];
13 int num,head[2001],n,k;
14 lol c,f[2001][4001],tmp[4001],size[2001],ans;
15 void add(int u,int v,lol dis)
16 {
17   num++;
18   edge[num].next=head[u];
19   head[u]=num;
20   edge[num].to=v;
21   edge[num].dis=dis;
22 }
23 void dfs(int x,int pa)
24 {int i,j,l;
25   size[x]=0;f[x][0]=0;
26   for (i=head[x];i;i=edge[i].next)
27     {
28       int v=edge[i].to;
29       if (v==pa) continue;
30       dfs(v,x);
31       for (j=0;j<=size[x]+size[v]+1;j++)
32       tmp[j]=2e14;
33       for (j=0;j<=size[x];j++)
34       {
35         for (l=0;l<=size[v];l++)
36           {
37             tmp[j+l]=min(tmp[j+l],f[x][j]+f[v][l]+edge[i].dis*(2-(l&1)));
38           }
39       }
40       size[x]+=size[v];
41       for (j=0;j<=size[x];j++)
42       f[x][j]=tmp[j];
43     }
44   size[x]++;
45   f[x][size[x]]=2e9;
46   for (i=size[x];i>=1;i--)
47     f[x][i]=min(f[x][i],f[x][i-1]);
48 }
49 int main()
50 {int u,v,i;
51   lol w;
52   while (cin>>n>>k>>c)
53     {num=0;
54       memset(head,0,sizeof(head));
55       memset(f,127/2,sizeof(f));
56       for (i=1;i<=n-1;i++)
57       {
58         scanf("%d%d%lld",&u,&v,&w);
59         u++;v++;
60         add(u,v,w);add(v,u,w);
61       }
62       dfs(1,0);
63       ans=2e14;
64       for (i=0;i<=k;i++)
65       ans=min(ans,f[1][2*i]+i*c);
66       cout<<ans<<endl;
67     }
68 }

 

 

posted @ 2018-03-29 20:38  Z-Y-Y-S  阅读(336)  评论(0编辑  收藏  举报