餐馆
Description
K妹的胡椒粉大卖,这辣味让食客们感到刺激,许多餐馆也买这位K妹的账。
有N家餐馆,有N-1条道路,这N家餐馆能相互到达。K妹从1号餐馆开始。每一个单位时间,K妹可以在所在餐馆卖完尽量多的胡椒粉,或者移动到有道路直接相连的隔壁餐馆。第i家餐馆最多需要A[i]瓶胡椒粉。K妹有M个单位的时间,问她最多能卖多少胡椒粉。
Input
第一行有两个正整数N,M。
第二行描述餐馆对胡椒粉的最大需求量,有N个正整数,表示A[i]。
接下来有N-1行描述道路的情况,每行两个正整数u、v,描述这条道路连接的两个餐馆。
Output
一个整数,表示她最多能卖的胡椒粉瓶数。
Sample Input
样例1输入
3 5
9 2 5
1 2
1 3
样例2输入
4 5
1 1 1 2
1 2
2 3
3 4
样例3输入
5 10
1 3 5 2 4
5 2
3 1
2 3
4 2
Sample Output
样例1输出
14
样例2输出
3
样例3输出
15
Data Constraint
对于10%的数据,N≤20。
对于50%的数据,N≤110。
对于100%的数据1 ≤ N, M ≤ 500,1 ≤ A[i]≤ 10^6。
Hint
在样例1的中,辣妹到达城市2后就恰好没时间卖辣椒粉了。
分析题目,通过观察我们可以发现,这是一个简单的树型动规。
题目大意是,有N个餐馆,N-1条道路使它们相连。因此,我们可以确定,这是一个无环图。
观察题目数据范围,节点个数N≤500,时间M≤500,我们就可以很容易的确定一个状态f[i][j]表示搜索到节点i时,第j秒钟所能得到的最大分数为f[i][j]。
但是,我们会发现,由于这道题目的图是一棵树,K妹从u向其中一条边(u,v1)走到v1去卖胡椒粉,所以其想要去v2卖胡椒粉,并且需要经过边(u,v2),必然要重新经过边(u,v1)回到u点,再从u点走(u,v2)到v2卖胡椒粉。
所以,我们不选择使用f[i][j]记录到点i,时间为j时所得到的分数。
那么,换一种思维,我们可以用f[i][t][k]来记录状态,表示从第i个点开始,花费了t秒时间,在节点i及其子树所能得到的最大分数,并且k=0时状态表示得到分数并且没有回到节点i,k=1表示得到f[i][t][k]的分数并且在t秒回到了节点i。
那么,我们就可以得到状态转移方程。
对于一个节点i本身,在其时间t内,它是否选择在自己节点售卖胡椒粉,转移方程为
f[i][t][k]=max(f[i][t][k],f[i][t-1][k])
对于一个节点i,在其时间t时,对于其任意的子节点j,在子节点j花费的时间t2(t2<t),有状态转移方程
f[i][t][0]=max(f[i][t][0],f[i][t-t2-1][1]+f[j][t2][0],f[i][t-t2-2][0]+f[j][t2][1])
f[i][t][1]=max(f[i][t][1],f[i][t-t2-2][1]+f[j][t2][1])
那么,我们在遍历所有点后,就可以直接寻找i=1时所有的f[i][t][k],记录下最大值ans,输出即可。
代码如下
#include <bits/stdc++.h>
#define LL long long int
using namespace std;
int n,m,tot;
LL ans;
LL f[510][510][2];
int q[510][510];
int tail[510];
int h[510],A[510];
bool bo[510];
struct node{
int to,next;
}v[1010];
void find(int );
void add(int ,int );
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&A[i]);
for (int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
}
find(1);
printf("%lld",ans);
return 0;
}
void find(int u)
{
bo[u]=true;
for (int jump=h[u];jump;jump=v[jump].next)
{
int w=v[jump].to;
if (!bo[w])
{
q[u][++tail[u]]=w;
find(w);
}
}
for (int i=1;i<=tail[u];i++)
{
int w=q[u][i];
for(int tu=m;tu;tu--)
for (int tw=1;tw<tu;tw++)
{
f[u][tu][0]=max(f[u][tu][0],(f[u][tu-tw-1][1]+f[w][tw][0]));
if (tu>=tw+2)
{
f[u][tu][0]=max(f[u][tu][0],(f[u][tu-tw-2][0]+f[w][tw][1]));
f[u][tu][1]=max(f[u][tu][1],(f[u][tu-tw-2][1]+f[w][tw][1]));
}
}
}
for (int i=m;i;i--)
{
f[u][i][0]=max(f[u][i][0],f[u][i-1][0]+A[u]);
f[u][i][1]=max(f[u][i][1],f[u][i-1][1]+A[u]);
if (u==1)
ans=max(ans,max(f[u][i][0],f[u][i][1]));
}
return ;
}
void add(int a,int b)
{
v[++tot].to=b;
v[tot].next=h[a];
h[a]=tot;
v[++tot].to=a;
v[tot].next=h[b];
h[b]=tot;
return ;
}