【HDU4003】 Find Metal Mineral | Tree dp, thinking

Main idea:

Given a tree with n nodes, the nodes are numbered 1~n, and each edge has a cost value.
There are k robots starting from point S, and ask the robot to traverse all the edges. What is the minimum cost?

Question idea:

I was stuck in the tree dp for two days, and I didn't know how to deal with the back edge at first.

Let's analyze it briefly:

Let dp[i][k] represent the subtree rooted at i, send out k traversed subtrees

In order to facilitate the processing of the back edge, the definition of the state is: Send out k traversed subtrees without returning, then k = 0 is naturally a case of back edges

Now consider the state of the back side:

For a subtree, all traversal is completed and then the root node is returned. The weight is the edge weight of the subtree and *2. Then when the subtree is traversed and returned to the parent node, should it return one robot or multiple? Obviously it is one, because the weights returned after traversing the subtree are the same, it is impossible to send more than one and then return, because there will be a few more root nodes to the node to send the robot path

After the problem is solved, a large part of the problem will be solved

Consider the k = 0,1,2,3,4,5,p of the subtree as the p types of items in each group. That is to say, for a node u, now it faces m groups (m is the number of children ), each group has p items. For each group, one item must be selected. Ask the smallest value?

Obviously it has become a knapsack problem, at this time the importance of k = 0 is reflected:

For edge e(u,e,w), the first state that can be determined is:

dp[u][k] += dp[e][0]*2*w

Why is it established? It is because a robot was sent to scan the subtree of e and returned, which is equivalent to not being ruled out. For the u node, k is still sent, which is also convenient for processing the next subtree when the backside problem of this subtree ( The first example)

And this ensures that one of each group of items must be selected

Next, traverse the other items in this group to see if it can affect the current dp[u][k].

for(int\ j=1;j<=k;j++)

\ \ \ \ \ \ \ \ \ \ \ \ \ dp[u][k] = min(dp[u][k],dp[u][k-j]+j*x.second+dp[e][j]);

In short, this question is not easy to do.

However, it is indeed a good question!

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17;
const ll maxn = 2e5+700;
const int mod= 1e9+7;
const int up = 1e9;
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
vector<pair<int,int>>v[maxn];
ll dp[maxn][12];
void dfs(int u,int fa){
    for(auto x:v[u]){
        int e = x.first;
        if(e == fa) continue;
        dfs(e,u);
        for(int k=p;k>=1;k--){///容量
            dp[u][k] += dp[e][0] + 2*x.second;///分配一个回来,保证选
            for(int j=1;j<=k;j++)
                dp[u][k] = min(dp[u][k],dp[u][k-j]+j*x.second+dp[e][j]);
        }
        dp[u][0] += dp[e][0] + 2*x.second;
    }
}
int main(){
    while(~scanf("%lld%lld%lld",&n,&m,&p)){
        for(int i=1;i<=n;i++) v[i].clear();
        for(int i=1;i<=n-1;i++){
            int x,y,w;read(x);read(y);read(w);
            v[x].push_back({y,w});
            v[y].push_back({x,w});
        }
        for(int i=1;i<=n;i++)
            for(int k=0;k<=p;k++)
                dp[i][k] = 0;
        dfs(m,m);
        printf("%lld\n",dp[m][p]);
    }
    return 0;
}

 

Guess you like

Origin blog.csdn.net/qq_43857314/article/details/111313348