【ssl1565】将功补过【树形DP】

Description

军事中心是一个严格的二叉树,也就是说,如果有个点可以分道,一定是分出,也只分出2条道路,现在Elvis Han正处在第一个分道处,也就是说树的根结点处。每条道路上都有一个分数,就是这个道路上的情报价值。但是他只有时间走M条路,他的最终情报价值总和就是他所经过的路的情报价值总和(假设他到过的路一定可以把所有情报得到)希望你给出一个方案使得他可以尽量多地获取情报以便将功补过。

Input

共有N行:
第一行:3个数据:N,M,Q(N表示有多少个路口,包括分道和不分道的路口;M表示他可以有时间走的道路总数;Q表示他的任务情报的价值)
第2~N行:每行3个数据,Xi,Yi,Wi (X,Y表示第I条道路连接的2个路口,W表示这条道路上的情报价值分, 注意,所有数据均在Lonint范围内)

Output

共包含2行:
第一行:输出TRUE/FALSE(注意大小写),表示他是否可以收集够任务情报价值
第二行:输出一个数据:
如果他可以完成任务,就输出他收集的情报总价值超过任务情报价值的部分。(正数)
如果不能完成任务,就输出一个数,表示他不能还差多少分才够任务情报价值。(负数)

Sample Input

【样例输入1】

3 1 10
1 2 10
1 3 8

【样例输入2】

9 3 49
6 2 15
7 2 10
8 7 6
7 9 15
1 3 20
2 1 10
4 3 8 
3 5 7

Sample Output

【样例输出1】

TRUE
0

【样例输出2】

FALSE
-4

Hint

<数据规模>
对于30%的数据 保证有N<=10
对于50%的数据 保证有N<=40
对于全部的数据 保证有 N<=100

分析

这题真的跟二叉苹果树一模一样!!
只需要最后加上一个判断答案是否超过任务情报的价值,按题目要求输出即可。

上代码

#include
#include
#include
#include
using namespace std;
int n,q,x,y,v,tot,h[101],e[101],f[101][101],s[101][101],p;
struct node
{
	int to,next;
}a[220];
void add(int x,int y)
{
	a[++tot]=(node){y,h[x]};
	h[x]=tot;
}
void dp(int k)
{
    e[k]=1;//记录当前节点已经被访问 
    for(int i=h[k];i>0;i=a[i].next)//,枚举边 
    {
    	if(e[a[i].to]==1) continue;//如果它的子节点已经被访问过,那就不用做了。 
    	dp(a[i].to);//递归 
    	for(int j=q;j>0;j--)//两个for类似01背包(选or不选且物品只有一个) 
    	{
    		for(int g=j-1;g>=0;g--)
    		{
    			f[k][j]=max(f[k][j],f[a[i].to][g]+f[k][j-g-1]+s[k][a[i].to]);
				// 这句详见博客 
    		}
    	}
    }
}
int main()
{
    cin>>n>>q>>p;
    for(int i=1;i<=n-1;i++)
    {
    	cin>>x>>y>>v;
    	add(x,y);
    	add(y,x);
    	s[x][y]=s[y][x]=v;//记录权值 
    }
    dp(1);
    if(f[1][q]>=p)
    {
    	cout<<"TRUE"<<endl<<f[1][q]-p;
    }
    else
    {
    	cout<<"FALSE"<<endl<<f[1][q]-p;
    }
	return 0;
}

你可能感兴趣的:(DFS,DP,SSL题库)