网上搜不着,八成又是哪个学长留下的……

因为考试第二题我们都好不容易才搞懂,学长有给我们扔了几道类似的题。

其实这道题思路挺好想的,就是一些细节还有复杂度比较难弄,好难调啊。

看到题的第一眼以为是树形背包,然后看到b的范围就放弃了。那咋办呢?首先第一维肯定是在树上某个节点,第二维呢?抓住小的干,f[i][j]表示在以i为根的子树里买j个物品花的最少钱数,但是其实还有一点没有考虑,就是子树能不能用优惠券决定于根节点买不买,再加半维?f[i][j][0]表示以i为根的子树里买j个物品花的最少钱数且i不买,f[i][j][1]表示以i为根的子树里买j个物品花的最少钱数且i买,正解就出来了。

 WA20代码:

    for(int i=f(x);i;i=n(i))
{
dfs(v(i));
size[x]+=size[v(i)];
for(int j=size[x];j;j--)
for(int k=;k<=size[v(i)];k++)
{
f[x][j][]=min(f[x][j][],f[v(i)][k][]+f[x][j-k][]);
f[x][j][]=min(f[x][j][],f[v(i)][k][]+f[x][j-k][]);
}
}

上面的代码是不是太简单了呀,显然忘东西了呀,WA50代码:

 void dfs(int x)
{
size[x]=;
f[x][][]=,f[x][][]=INF,f[x][][]=c[x],f[x][][]=c[x]-d[x];
if(!f(x))return;
for(int i=f(x);i;i=n(i))
{
dfs(v(i));
size[x]+=size[v(i)];
for(int j=size[x];j;j--)
for(int k=;k<=size[v(i)]&&k<=j;k++)
{
f[x][j][]=min(min(f[x][j][],f[v(i)][k][]+f[x][j-k][]),min(f[v(i)][j][],f[v(i)][k][]+f[x][j-k][]) );
if(j!=k)
f[x][j][]=min(f[x][j][],f[v(i)][k][]+f[x][j-k][]);
if(j!=k&&j>&&k>) f[x][j][]=min(f[x][j][], min(f[v(i)][j-][]+c[i]-d[i],f[x][k][]+f[v(i)][j-k][]) );
}
}
}

上面的代码少考虑了在儿子节点不买儿子节点但是卖儿子节点的儿子的情况,改完之后T70的代码:

 void dfs(int x)
{
size[x]=;
f[x][][]=,f[x][][]=INF,f[x][][]=c[x],f[x][][]=c[x]-d[x];
if(!f(x))return;
for(int i=f(x);i;i=n(i))dfs(v(i));
for(int i=f(x);i;i=n(i))
{
size[x]+=size[v(i)];
for(int j=size[x];j>=;j--)
for(int k=min(size[v(i)],j);k>=;k--)
{
f[x][j][]=min(min(f[x][j][],f[v(i)][k][]+f[x][j-k][]),min(f[v(i)][j][],f[v(i)][k][]+f[x][j-k][]));
if(j!=k)f[x][j][]=min( min(f[x][j][],f[v(i)][k][]+f[x][j-k][]) ,f[v(i)][k][]+f[x][j-k][]);
if(j!=k&&j>&&k>) f[x][j][]=min(f[x][j][], f[x][k][]+f[v(i)][j-k][] );
}
}
}

其实已经改对了,但是这样的复杂度是$n^3$的,size先加是$n^3$,size后加才是$n^2$,其实就相当于是枚举点对数,所以是$n^2$,但是我这份代码不能在后面加,平局每次j都比后加多枚举一颗子树,所以我尝试着卡一卡,给儿子排序,打的放后边,虽然快了一点,但还是T了,所以又开始了艰辛的改代码,又一次T70:

 void dfs(int x)
{
size[x]=;
f[x][][]=,f[x][][]=INF,f[x][][]=c[x],f[x][][]=c[x]-d[x];
if(!f(x))return;
for(int i=f(x);i;i=n(i))dfs(v(i));
for(int i=f(x);i;i=n(i))
{
size[x]+=size[v(i)];
memset(tmp,0x3f,sizeof(tmp));
for(int j=;j<=size[x];j++)
for(int k=;k<=size[v(i)]&&j+k<=size[x]+size[v(i)];k++)
{
tmp[j+k][]=min(min(tmp[j+k][],f[v(i)][k][]+f[x][j][]),min(f[v(i)][j+k][],f[v(i)][k][]+f[x][j][]));
if(j)tmp[j+k][]=min(min(tmp[j+k][],f[v(i)][k][]+f[x][j][]),f[v(i)][k][]+f[x][j][]);
   if(j+k!=k&&j+k>&&k>) tmp[j+k][]=min(tmp[j+k][],f[x][k][]+f[v(i)][j][]);
}
for(int j=;j<=size[x];j++)
f[x][j][]=min(f[x][j][],tmp[j][]),f[x][j][]=min(f[x][j][],tmp[j][]);
}
}

向上次那样的枚举顺序不能把size放到后边,要枚举j,k向j+k转移,而且这样还要用到辅助数组……

为啥这样还是不能吧size+放到下边呢?把代码中加粗部分加上就行了,我也不知道当时为啥这么沙雕……

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define MAXN 5010
#define LL long long
#define INF 1000000010
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int L=1<<20|1;
char buffer[L],*S,*T;
#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
struct edge
{
int u,v,nxt;
#define u(x) ed[x].u
#define n(x) ed[x].nxt
#define v(x) ed[x].v
}ed[1000000];
int first[MAXN],num_e;
#define f(x) first[x]
struct sor
{int size,id;
friend bool operator < (sor a,sor b)
{
return a.size>b.size;
}
}so[MAXN];
int n,b;
int c[MAXN],d[MAXN],x[MAXN];
int f[MAXN][MAXN][2],size[MAXN];
void dfs1(int x)
{
so[x].size=1;so[x].id=x;
for(int i=f(x);i;i=n(i))
dfs1(v(i)),so[x].size+=so[v(i)].size;
}
int tmp[MAXN][2];
void dfs(int x)
{
size[x]=1;
f[x][0][0]=0,f[x][0][1]=INF,f[x][1][0]=c[x],f[x][1][1]=c[x]-d[x];
if(!f(x))return;
for(int i=f(x);i;i=n(i))dfs(v(i));
tmp[0][0]=0,tmp[0][1]=INF,tmp[1][0]=c[x],tmp[1][1]=c[x]-d[x];
for(int i=f(x);i;i=n(i))
{
memset(tmp,0x3f,sizeof(tmp));
for(int j=0;j<=size[x]+1;j++)
for(int k=0;k<=size[v(i)]+1&&j+k<=size[x]+size[v(i)];k++)
{
tmp[j+k][0]=min(min(tmp[j+k][0],f[v(i)][k][0]+f[x][j][0]),min(f[v(i)][j+k][0],f[v(i)][k][0]+f[x][j][0]));
if(j)tmp[j+k][1]=min(min(tmp[j+k][1],f[v(i)][k][1]+f[x][j][1]),f[v(i)][k][0]+f[x][j][1]);
if(j+k!=k&&j+k>1&&k>1) tmp[j+k][1]=min(tmp[j+k][1],f[x][k][1]+f[v(i)][j][0]);
}
size[x]+=size[v(i)];
for(int j=0;j<=size[x];j++)
f[x][j][0]=min(f[x][j][0],tmp[j][0]),f[x][j][1]=min(f[x][j][1],tmp[j][1]);
}
}
inline int read()
{
int s=0;char a=getchar();
while(a<'0'||a>'9')a=getchar();
while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();}
return s;
}
inline void add(int u,int v);
signed main()
{
// freopen("in.txt","r",stdin); n=read(),b=read();
for(int i=1;i<=n;i++)
{
if(i==1)c[i]=read(),d[i]=read();
else
{
c[i]=read(),d[i]=read(),x[i]=read();
add(x[i],i);
}
}
dfs1(1);
sort(so+1,so+n+1);
memset(ed,0,sizeof(ed));memset(first,0,sizeof(first));num_e=0;
for(int i=2;i<=n;i++)
add(x[so[i].id],so[i].id);
dfs1(1);
memset(f,0x3f,sizeof(f));
dfs(1);
for(int i=1;i<=n;i++)
{
if(min(f[1][i][1],f[1][i][0])>b)
{printf("%d\n",i-1);return 0;}
}
cout<<n<<endl;
}
inline void add(int u,int v)
{
++num_e;
u(num_e)=u;
v(num_e)=v;
n(num_e)=f(u);
f(u)=num_e;
}

HZOI 可怜与超市的更多相关文章

  1. HZOI 可怜与超市 树形dp

    学长留的题,质量还是灰常高的. 而且我树规本身较弱,一道也不想放下 题目链接:https://www.cnblogs.com/Juve/articles/11203824.html 题解:这道题我们可 ...

  2. 树上染色+可怜与超市(树状DP)

    这两道题是学长精心准备的,想了很长时间,比较经典. 第一题 树上染色 有一棵点数为 N的树,树边有边权.给你一个在 0∼N之内的正整数 K,你要在这棵树中选择 K 个点,将其染成黑色,并将其他的 N− ...

  3. 一些树上dp的复杂度证明

    以下均为内网 树上染色 https://www.lydsy.com/JudgeOnline/problem.php?id=4033 可怜与超市 http://hzoj.com/contest/62/p ...

  4. 高二小假期集训—D5

    刚调完了一个非常恶心的题(可能是我写的太恶心了),心累……先写会博客吧. 今天上午该完了考试的三道题,感觉第二道真的是个好题(学长说是经常会遇到的一类题……完了完了),看了一个小时std才看懂,写了篇 ...

  5. NOIP模拟测试5「星际旅行·砍树·超级树」

    星际旅行 0分 瞬间爆炸. 考试的时候觉得这个题怎么这么难, 打个dp,可以被儿子贡献,可以被父亲贡献,还有自环,叶子节点连边可以贡献,非叶子也可以贡献,自环可以跑一回,自环可以跑两回, 关键是同一子 ...

  6. 大三作品:不需要售货员的超市? Easy-Shopping超市导购系统

    本来么,逛超市是一件很爽的事情,拉上父母孩子,推个大推车,一边聊一边买,然后开开心心的回家去. 可到了旺季,逛超市可就麻烦了,买东西人挤人,到结算的地方人山人海,一刷卡,我去,怎么这个卫生纸这么贵!这 ...

  7. Azure IoT带来更高效的新能源生产和会看人脸色的无人超市

    全球分析机构都认为物联网将在未来几年呈现爆发式增长,到2020年,各种传感器.新型物联网设备,再加上传统PC.智能手机.平板电脑.网络电视,以及各类可穿戴智能设备,将交织成一个由300亿到500亿台设 ...

  8. 互联网+下PDA移动智能手持POS超市收银开单软件

    是一套专为中小超市.专卖店设计的收银管理软件,广泛应用于中小超市(百货商店).化妆品店.婴幼儿用品店.玩具店.保健品店.茶叶店. 电器.文具图书.手机通讯器材店等行业的中小型店面店铺.该系统具有完善的 ...

  9. 美萍超市销售管理系统标准版access数据库密码mp611

    美萍超市销售管理系统标准版access数据库密码mp611 作者:admin  来源:本站  发表时间:2015-10-14 19:01:43  点击:199 美萍超市销售管理系统标准版access后 ...

随机推荐

  1. 【Scala学习笔记】一、函数式编程的思想

    1. 函数是头等值.     在函数编程中,函数也是值,与整数和字符串处于同一地位.函数可以像变量一样被创建,修改,并当成变量一样传递,返回或是在函数中嵌套函数. 函数可以当做参数传递给其他函数.   ...

  2. Linxu SSH登陆出现Access Denied错误的解决方法

    其实这个问题是从 SCP 过来的.用 SCP 在两台 Linux 服务器之间传送备份文件.输入完 root 密码后,总是出现 Permission denied, please try again.  ...

  3. Java借助itext pdf生成固定格式pdf的模板工具类

    这里是标题区域 这里是副标题1: 副标题的内容 这里是副标题2: 这里是副标题2的内容 这里是副标题3: 这里是副标题3的内容 序号 表头1 复合表头 表头2 子表头1 子表头2 子表头3 1 居左内 ...

  4. 2019-9-2-win10-uwp-存放网络图片到本地

    title author date CreateTime categories win10 uwp 存放网络图片到本地 lindexi 2019-09-02 12:57:38 +0800 2018-2 ...

  5. Leetcode501.Find Mode in Binary Search Tree二叉搜索树中的众数

    给定一个有相同值的二叉搜索树(BST),找出 BST 中的所有众数(出现频率最高的元素). 假定 BST 有如下定义: 结点左子树中所含结点的值小于等于当前结点的值 结点右子树中所含结点的值大于等于当 ...

  6. TP5.1 首页路由

    把自带的return 删了

  7. 洛谷 P1892 [BOI2003]团伙

    题目描述 1920年的芝加哥,出现了一群强盗.如果两个强盗遇上了,那么他们要么是朋友,要么是敌人.而且有一点是肯定的,就是: 我朋友的朋友是我的朋友: 我敌人的敌人也是我的朋友. 两个强盗是同一团伙的 ...

  8. 【JZOJ3598】【CQOI2014】数三角形

    Mission 对于100%的数据1<=m,n<=1000 Solution 鬼题,ans=C3(n∗m)−Ans,其中Ans表示三点共线的数目: 枚举最长边的向量(x,y),容易算出贡献 ...

  9. 注解1 --- JDK内置的三个基本注解 --- 技术搬运工(尚硅谷)

    @Override: 限定重写父类方法, 该注解只能用于方法 @Deprecated: 用于表示所修饰的元素(类, 方法等)已过时.通常是因为所修饰的结构危险或存在更好的选择 @SuppressWar ...

  10. Docker.[1].环境准备.

    Docker.[1].环境准备. 环境描述: 在笔记本中安装了虚拟机,虚拟机中又安装了RedHat 7.x操作系统,然后在这个RedHat7.x的操作系统上,进行安装Docker. 虚拟机中的操作系统 ...