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;
}



你可能感兴趣的:(Suzhou Adventure)