• BZOJ4987:Tree (树形DP)


    Description

    从前有棵树。
    找出K个点A1,A2,…,Ak。
    使得∑dis(AiAi+1),(1<=i<=K-1)最小。

    Input

    第一行两个正整数n,k,表示数的顶点数和需要选出的点个数。
    接下来n-l行每行3个非负整数x,y,z,表示从存在一条从x到y权值为z的边。
    I<=k<=n。
    l<x,y<=n
    1<=z<=10^5
    n <= 3000

    Output

    一行一个整数,表示最小的距离和。

    Sample Input

    10 7
    1 2 35129
    2 3 42976
    3 4 24497
    2 5 83165
    1 6 4748
    5 7 38311
    4 8 70052
    3 9 3561
    8 10 80238

    Sample Output

    184524

    思路:求大小为K的连通块的最小遍历距离,最小值显然等于边权之和*2-直径。 我们利用这个来DP,用dp[i][j]表示i子树有j个直径的端点(i<=N,j<=2); 如果我i子树有两个直径端点,则当前边不在直径上,如果子树有一个直径端点,则当前边再直径上....其他类似

    然后就不难得到方程。 注意合并的时候要01像背包一样从大到小,以免一个数用两次。  (或者用一个临时变量数组)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=3010;
    int Laxt[maxn],Next[maxn<<1],To[maxn<<1],Len[maxn<<1],cnt;
    int N,K,sz[maxn],dp[maxn][maxn][3],ans;
    void add(int u,int v,int w){
        Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=w;
    }
    void dfs(int u,int fa){
        sz[u]=1; dp[u][1][0]=0; dp[u][1][1]=0; dp[u][1][2]=0;
        for(int i=Laxt[u];i;i=Next[i]){
            int v=To[i]; if(v==fa) continue;
            dfs(v,u);
            for(int j=sz[u];j>=0;j--){
                for(int k=sz[v];k>=0;k--){
                    dp[u][j+k][2]=min(dp[u][j+k][2],dp[u][j][0]+dp[v][k][2]+2*Len[i]);
                    dp[u][j+k][2]=min(dp[u][j+k][2],dp[u][j][1]+dp[v][k][1]+Len[i]);
                    dp[u][j+k][2]=min(dp[u][j+k][2],dp[u][j][2]+dp[v][k][0]+2*Len[i]);
    
                    dp[u][j+k][1]=min(dp[u][j+k][1],dp[u][j][0]+dp[v][k][1]+Len[i]);
                    dp[u][j+k][1]=min(dp[u][j+k][1],dp[u][j][1]+dp[v][k][0]+2*Len[i]);
    
                    dp[u][j+k][0]=min(dp[u][j+k][0],dp[u][j][0]+dp[v][k][0]+2*Len[i]);
                }
            }
            sz[u]+=sz[v];
        }
        ans=min(ans,dp[u][K][2]);
    }
    int main()
    {
        int u,v,w;
        scanf("%d%d",&N,&K);
        memset(dp,0x3f,sizeof(dp));
        for(int i=1;i<N;i++){
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w); add(v,u,w);
        }
        ans=0x3f3f3f3f;
        dfs(1,0);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    心情记录&考试总结 3.30
    BZOJ 1982 Moving Pebbles
    BZOJ 3759 Hungergame
    51Nod 算法马拉松12 Rikka with sequences
    51Nod 算法马拉松12 移数博弈
    BZOJ 3720 gty的妹子树
    BZOJ 4184 shallot
    BZOJ 3160 万径人踪灭
    好好学习天天向上
    java解析json字符串
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9945347.html
Copyright © 2020-2023  润新知