一道题18

$n \leq 2000$的树,问从原点出发把每条边走至少一次再回到原点最少代价,有边权。其中可以使用$k$次传送门,始末位置不限,一次代价为$c$。

如果没有$k$的话直接每条边走两次。由于传送一次相当于一条链不用走,搞出来应该是求$k$条边不相交链的最大权和(相交的话,相交部分走了两次,相当于没优化过)。

树形dp,$f(i,j,0/1)$--子树$i$,已经有$j$条链完整覆盖了的最大权和,0/1表示是否能够伸一条不完整的链往上(以便在某个祖先处和另一条不完整链拼接)。分若干种情况转移。

背包容量严格等于子树大小时,这样的复杂度是$n^2$的。

 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 //#include<time.h>
 5 //#include<complex>
 6 //#include<set>
 7 //#include<queue>
 8 //#include<vector>
 9 #include<algorithm>
10 #include<stdlib.h>
11 using namespace std;
12 
13 #define LL long long
14 int qread()
15 {
16     char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
17     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
18 }
19 
20 //Pay attention to '-' , LL and double of qread!!!!
21 
22 int n,C,K;
23 #define maxn 4011
24 struct Edge{int to,next,v;}edge[maxn<<1]; int first[maxn],le=2;
25 void in(int x,int y,int v) {Edge &e=edge[le]; e.to=y; e.v=v; e.next=first[x]; first[x]=le++;}
26 void insert(int x,int y,int v) {in(x,y,v); in(y,x,v);}
27 
28 int f[maxn][maxn][2],g[maxn][2],size[maxn];
29 void dp(int x,int fa)
30 {
31     memset(f[x],0,sizeof(f[x]));
32     size[x]=0;
33     for (int i=first[x];i;i=edge[i].next)
34     {
35         Edge &e=edge[i]; if (e.to==fa) continue;
36         dp(e.to,x);
37         for (int j=size[x]+size[e.to];~j;j--) g[j][0]=f[x][j][0],g[j][1]=f[x][j][1];
38         for (int j=size[x];~j;j--)
39             for (int k=1;k<=size[e.to];k++)
40                 g[j+k][0]=max(g[j+k][0],f[x][j][1]+f[e.to][k-1][1]+e.v);
41         for (int j=size[x];~j;j--)
42             for (int k=0;k<=size[e.to];k++)
43                 g[j+k][1]=max(g[j+k][1],f[x][j][0]+f[e.to][k][1]+e.v);
44         for (int j=size[x];~j;j--)
45             for (int k=0;k<=size[e.to];k++)
46                 g[j+k][1]=max(g[j+k][1],f[x][j][1]+f[e.to][k][0]);
47         for (int j=size[x];~j;j--)
48             for (int k=0;k<=size[e.to];k++)
49                 g[j+k][0]=max(g[j+k][0],f[x][j][0]+f[e.to][k][0]);
50         size[x]+=size[e.to];
51         for (int j=size[x];~j;j--) f[x][j][0]=g[j][0],f[x][j][1]=g[j][1];
52     }
53     for (int i=0;i<=size[x];i++) f[x][i][1]=max(f[x][i][1],f[x][i][0]);
54     if (x==1) for (int i=0;i<size[x];i++) f[x][i+1][0]=max(f[x][i+1][0],f[x][i][1]);
55     size[x]++;
56 }
57 int main()
58 {
59 //    freopen("mzz.in","r",stdin);
60 //    freopen("mzz.out","w",stdout);
61     while (~scanf("%d",&n))
62     {
63         K=qread(); C=qread(); le=2; memset(first,0,sizeof(first));
64         for (int i=1,x,y,v;i<n;i++) {x=qread()+1; y=qread()+1; v=qread(); insert(x,y,v);}
65         dp(1,0);
66         int ans=0,tot=0;
67         for (int i=2;i<le;i++) tot+=edge[i].v;
68         ans=tot;
69         for (int i=0;i<=K;i++) ans=min(ans,tot-f[1][i][0]+C*i);
70         printf("%d\n",ans);
71     }
72     return 0;
73 }
View Code

 

posted @ 2018-06-13 18:59  Blue233333  阅读(186)  评论(0编辑  收藏  举报