Suzhou Adventure

描述

Little Hi is taking an adventure in Suzhou now. There are N beautiful villages in Suzhou which are numbered from 1 to N. They connected by N-1 roads in such a way that there is excactly one way to travel from one village to another. Little Hi gives each village a score according to its attractiveness. He is visiting village 1 now and plans to visit excatly M villages (including village 1) and maxize the total score of visited villages. Further more, K villages are recommended by Little Ho. He does not want to miss these recommended villages no matter what their attractiveness scores are.

Note that Little Hi visits every village on his travel route. Passing a village without visiting it is not allowed. Please find the maximum total score Little Hi can get.

輸入

The first line contains 3 integers N(1 <= N <= 100), K(1 <= K <= 5) and M(1 <= M <= N), representing the number of villages, the number of recommended villages and the number of villages Little Hi plans to visit.
The second line contains N integers, the attractiveness scores of villages. The scores are between 1 to 100.
The third line contains K integers, the list of recommended villages.
The following N-1 lines each contain two integers a and b, indicating that village a and village b are connected by a road.

輸出

The maximum scores Little Hi can get. If there is no solution output -1.

樣例輸入
5 2 4
1 2 3 4 5
3 4
1 2
1 3
1 4
2 5
樣例輸出
10

這道題有兩個條件:

1.所走的點的個數不能超過m個;

2.必須走那些推薦的點。

不能超過m個點就直接樹形dp就好了,

可是需要走那些推薦的點,

做法:

將這些要走的推薦點直接走掉,並

將其所以祖父節點的值全部累加,統計個數並

標記,看其個數是否超過m了,不過在操作時需要

將多叉樹轉換成二叉樹,記住一點建立二叉樹後的

右子樹實際上是左子樹的兄弟。

調試了幾個小時,真累。

#include <stdio.h>
#include <vector>
#include <string.h>
#define DBUG printf ( "Here!\n" )
using namespace std;
const int maxn = 205;
struct node
{
    int l, r, socre;
} a[maxn];
int son[maxn], vis[maxn], use[maxn];
int dp[maxn][maxn], ans, to[maxn], m, fa[maxn];
vector < int > mp[maxn];
inline int Max ( int a, int b )
{
    return a > b ? a : b;
}
void create_tree ( int u )  //轉換成二叉樹
{
    int size = mp[u].size ( );
    vis[u] = 1;
    for ( int i = 0; i < size; i ++ )
    {
        int v = mp[u][i];
        if ( vis[v] )
            continue ;
        if ( fa[v] == -1 )
            fa[v] = u;
        if ( a[u].l == -1 )
            a[u].l = v;
        else
            a[ son[u] ].r = v;
        son[u] = v;
        create_tree ( v );
    }
}
void front_print ( int u )
{
    printf ( "%d ", u );
    if ( a[u].l != -1 )
        front_print ( a[u].l );
    if ( a[u].r != -1 )
        front_print ( a[u].r );
}
int dfs ( int i, int j )
{
    if ( dp[i][j] != -1 )
        return dp[i][j];
    if ( j == 0 )
        return 0;
    int val = 0, add = 0;
    if ( use[i] == 0 )
    {
        val = a[i].socre;
        add = -1;
    }
    if ( a[i].l == -1 && a[i].r == -1 )
        return dp[i][j] = val;
    if ( a[i].l > 0 && a[i].r == -1 )
        dp[i][j] = val+dfs ( a[i].l, j+add );
    else if ( a[i].l == -1 && a[i].r > 0 )
        dp[i][j] = Max ( val+dfs ( a[i].r, j+add ), dfs ( a[i].r, j ) );
    else
    {
        dp[i][j] = Max ( dfs ( a[i].r, j ), val+dfs ( a[i].l, j+add ) );
        //add可能爲0,那麼左子樹就需要走a[i].l,j(一直錯在這裏)
        for ( int k = 0; k < j; k ++ )
        //**而且不能加<=j,因爲add爲-1的情況也需要考慮,所以放上面做一次
        {
            //printf ( "%d\n", k );
            dp[i][j] = Max ( dp[i][j], val+dfs ( a[i].l, k )+dfs ( a[i].r, j-k+add ) );
        }
    }
    //printf ( "%d %d %d %d %d %d\n", i, j, a[i].l, a[i].r, add, dp[i][j] );
    return dp[i][j];
}
void get_tag ( int u )
{
    while ( ~ u )
    {
        //printf ( "%d\n", v );
        if ( use[u] == 0 )
        {
            ans = ans+a[u].socre;   //加值 並個數減1
            m --;
            use[u] = 1; //標記節點,證明已用
        }
        u = fa[u];
    }
}
int main ( )
{
    int n, k, u, v;
    memset ( son, -1, sizeof ( son ) );
    memset ( fa, -1, sizeof ( fa ) );
    memset ( dp, -1, sizeof ( dp ) );
    memset ( use, 0, sizeof ( use ) );
    scanf ( "%d%d%d", &n, &k, &m );
    for ( int i = 1; i <= n; i ++ )
    {
        scanf ( "%d", &a[i].socre );
        a[i].l = a[i].r = -1;
    }
    for ( int i = 1; i <= k; i ++ )
        scanf ( "%d", &to[i] );
    for ( int i = 1; i < n; i ++ )
    {
        scanf ( "%d%d", &u, &v );
        mp[u].push_back ( v );
        mp[v].push_back ( u );
    }
    create_tree ( 1 );
    for ( int i = 1; i <= k; i ++ )
        get_tag ( to[i] );  //將to[i]的父節點全部加起來並標記
    //printf ( "%d %d\n", ans, m );
    //front_print ( 1 );
    if ( m < 0 )    //這些必須走的點需要走的次數超過m
        printf ( "-1" );
    else
    {
        ans = ans+dfs ( 1, m );
        printf ( "%d", ans );
    }
    return 0;
}



發佈了20 篇原創文章 · 獲贊 21 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章