HDU 4003 Find Metal Mineral

Problem Description
Humans have discovered a kind of new metal mineral on Mars which are distributed in point‐like with paths connecting each of them which formed a tree. Now Humans launches k robots on Mars to collect them, and due to the unknown reasons, the landing site S of all robots is identified in advanced, in other word, all robot should start their job at point S. Each robot can return to Earth anywhere, and of course they cannot go back to Mars. We have research the information of all paths on Mars, including its two endpoints x, y and energy cost w. To reduce the total energy cost, we should make a optimal plan which cost minimal energy cost.

Input
There are multiple cases in the input.
In each case:
The first line specifies three integers N, S, K specifying the numbers of metal mineral, landing site and the number of robots.
The next n‐1 lines will give three integers x, y, w in each line specifying there is a path connected point x and y which should cost w.
1<=N<=10000, 1<=S<=N, 1<=k<=10, 1<=x, y<=N, 1<=w<=10000.

Output
For each cases output one line with the minimal energy cost.

解題思路:經典樹形DP。這道題的在進行狀態轉移的時候需要用到貪心的思想,想到這兩個貪心的地方,狀態轉移便好寫,如果想不到,狀態轉移就不好搞了。(1)對於當前子樹根節點u,如果我們分配給其x個機器人(x>1)且這x個機器人在遍歷完子樹之後全部返回到根節點的花費肯定大於等於只有1個機器人遍歷這棵子樹然後返回到根節點。(2)如果我們分配給其x個機器人且我們只讓其中的y個機器人返回,則這種方案的花費是大於等於我們讓(x-y)個機器人遍歷這棵子樹且不返回到根節點的花費的。這兩個貪心的地方搞明白了,則我們的狀態轉移便好寫了,設dp[u][i]表示給根節點u分配i個機器人遍歷完整棵子樹需要的最少花費,則對於當前u的一個子節點v,我們採用的方案由貪心規則可知是隻存在兩種情況的即(1)讓一個節點去遍歷整棵子樹遍歷完之後返回到根節點(2)給該子樹分配x個機器人去遍歷且不返回到根節點。這樣我們便可以輕鬆地寫出樹形DP的代碼。

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <functional>
using namespace std;
const int maxn = 10010;
typedef long long ll;
int N, S, K;

struct Edge {
    int v, w, next;
    Edge() { }
    Edge(int _v, int _w, int _next) : v(_v), w(_w), next(_next) { }
}edges[2*maxn];
int head[maxn], edge_sum;

void init_graph() {
    edge_sum = 0;
    memset(head, -1, sizeof(head));
}

void add_edge(int u, int v, int w) {
    edges[edge_sum].v = v;
    edges[edge_sum].w = w;
    edges[edge_sum].next = head[u];
    head[u] = edge_sum++;

    edges[edge_sum].v = u;
    edges[edge_sum].w = w;
    edges[edge_sum].next = head[v];
    head[v] = edge_sum++;
}

ll dp[maxn][12];

void dfs(int u, int fa) {

    for(int i = head[u]; i != -1; i = edges[i].next) {
        int v = edges[i].v;
        int w = edges[i].w;
        if(v == fa) continue;
        dfs(v, u);
        for(int j = K; j >= 1; --j) {
            dp[u][j] += (dp[v][0] + 2 * w);
            for(int k = 1; k <= j; ++k) {
                //printf("Test: %I64d %I64d %I64d\n", dp[u][j], dp[u][j-k], dp[v][k] + k * w);
                dp[u][j] = min(dp[u][j], dp[u][j-k] + dp[v][k] + k * w);
            }
        }
        dp[u][0] += (dp[v][0] + 2 * w);
    }
    return ;
}

int main() {

    //freopen("aa.in", "r", stdin);
    int u, v, w;
    while(scanf("%d %d %d", &N, &S, &K) != EOF) {
        init_graph();
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i < N; ++i) {
            scanf("%d %d %d", &u, &v, &w);
            add_edge(u, v, w);
        }
        dfs(S, -1);
        printf("%I64d\n", dp[S][K]);
    }
    return 0;
}
發佈了230 篇原創文章 · 獲贊 2 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章