• 【解题报告】CF815C


    【解题报告】CF815C

    题目大意

    Kellen想要买 (n) 件东西,她有 (b) 块钱,实际上,超市也就只有 (n) 件东西,超市为Kellen准备了 (n) 种优惠券,但是对于除第一件商品以外的优惠券,必须在使用第 (x_i) 张优惠券之后方才可以使用,你能帮她了解一下在不超过她手上的钱的情况下,她最多能买多少东西

    输入第一行两个整数,(n)(b)

    从第二行到第 (n+1) 行,除第二行前两个整数之外,后面的每行三个整数 $c_i space,d_i space $ 和 (x_i)

    字母意义皆如题目所示

    思路

    这道题目,我们可以从必须使用 (x_i) 之后才可以使用 (i) 知道,这个类似于没有上司的舞会,或者是选课,因此我们要使用树形DP

    按照之前的惯例,我们可以设置如下状态

    设置 (f[i][j][0/1]) 表示在以 (i) 为根的子树中,选择 (j)​ 个物品,在第 $i $ 个商品上面是否使用优惠券可以最多购买东西的数量

    然后我们根据定义,我们可以列出如下初始状态

    • (x)​ 个节点的子树不购买,他自己也不购买,不使用优惠券,没有代价
    • (x) 个节点的子树不购买,购买他自己,但是也不使用优惠券,代价是买 (x) 花的钱 (c_x)
    • (x) 个节点地字数不购买,购买他自己,使用优惠券,这样他们的代价就是 (c_x-d_i)

    所以我们的初始状态就定义完了

    然后想动态转移方程

    怎么想呢,枚举自己的大小和子树和他所有儿子的大小

    我们可以有

    [f[x][i+j][0]=min(f[x][i+j][0],f[x][i][0]+f[son][j][0]) ]

    这个的意思呢就是x节点有 (i+j) 个节点,然后选除了某个子树外的 (i)​ 个节点的买的数量和买这某个子树的 (j) 个节点的总的可以买的

    [f[x][i+j][1]= min egin{cases} f[x][i][1]+f[son][j][0] \ f[x][i][1]+f[son][j][1] end{cases} ]

    这个方程的意思和上面的差不多,也就不做过多解释了

    因此我们对着是输入的数据疯狂建树,然后将自己的边指向需要自己的节点,然后我们跑一边 dfs 就可以把树形DP写完了

    代码

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <string>
    using namespace std;
    const int maxn=5005;
    int n,b,ans;
    int c[maxn],d[maxn];
    int x[maxn];
    
    int size[maxn],f[maxn][maxn][5];
    
    struct edge{
    	int e,next;
    }ed[maxn<<1];
    int en,first[maxn];
    void add_edge(int s,int e)
    {
    	en++;
    	ed[en].next=first[s];
    	first[s]=en;
    	ed[en].e=e;
    }
    void dfs(int x)
    {
    	size[x]=1;
    	f[x][0][0]=0;
    	f[x][1][0]=c[x];
    	f[x][1][1]=c[x]-d[x];
    	for(int i=first[x];i;i=ed[i].next)
    	{
    		int e=ed[i].e;
    		dfs(e);
    		for(int i=size[x];i>=0;i--)
    		{
    			for(int j=0;j<=size[e];j++)
    			{
    				f[x][i+j][0]=min(f[x][i+j][0],f[x][i][0]+f[e][j][0]);
    				f[x][i+j][1]=min(f[x][i+j][1],min(f[x][i][1]+f[e][j][0],f[x][i][1]+f[e][j][1]));
    			}
    		}
    		size[x]+=size[e];
    	}
    }
    int main()
    {
    	memset(f,0x3f3f3f,sizeof(f));
    	cin>>n>>b;
    	cin>>c[1]>>d[1];
    	for(int i=2;i<=n;i++)
    	{
    		cin>>c[i]>>d[i]>>x[i];
    		add_edge(x[i],i);
    	}
    	dfs(1);
    	for(int i=n;i>=1;i--)
    	{
    		if(f[1][i][0]<=b||f[1][i][1]<=b)
    		{
    			ans=i;
    			break;
    		}
    	}
    	cout<<ans<<'
    ';
    	return 0;
    }
    
    本博文为wweiyi原创,若想转载请联系作者,qq:2844938982
  • 相关阅读:
    css 三种布局定位
    居中布局注意的要点
    CSS盒子3D模型
    SpringMVC中JSP取不到ModelAndView的数据原因
    如何让 height:100%; 起作用
    css形变
    消除html元素之间空白
    h5移动端网页头部标签模板
    大数据之Hadoop核心之HDFS
    大数据之Hadoop集群搭建
  • 原文地址:https://www.cnblogs.com/wweiyi2004/p/15364840.html
Copyright © 2020-2023  润新知