zoukankan      html  css  js  c++  java
  • 一道题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
    ",ans);
    71     }
    72     return 0;
    73 }
    View Code
  • 相关阅读:
    mysql2redis
    butterknife简化android开发
    加速 Gradle 构建大型 Android 项目的方法[转]
    大型项目 Gradle 的常用库和版本管理[转]
    JVM调优
    CSDN上最火的android项目
    jOOQ
    Guava库
    Android 镜像地址[持续更新中]
    The server quit without updating PID file (mysql.pid)一次意外mysql停止运行备忘录
  • 原文地址:https://www.cnblogs.com/Blue233333/p/9179347.html
Copyright © 2011-2022 走看看