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

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

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

看到题的第一眼以为是树形背包,然后看到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. springmvc 支持对象与json 自动转换的配置

    基于maven的工程, 需要在pom.xml中添加如下依赖 <dependency> <groupId>javax.servlet</groupId> <ar ...

  2. python中操作json

    1.导入json包 import json 2.打开json文档 fp = open(jsonpath) 3.读取json文件 data=json.load(fp) 4.获取json的值 data[' ...

  3. 洛谷 P1951 收费站_NOI导刊2009提高(2) 最短路+二分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 思路 AC代码 总结 题面 题目链接 P1951 收费站_NOI导刊2009提高(2) 其 ...

  4. 交互题(apio2016Gap)

    题目链接   //Serene #include<algorithm> #include<iostream> #include<cstring> #include& ...

  5. 数据库Mysql监控及优化

    在做 性能测试的时候数据最重要,数据来源于哪里呢,当然是数据库了,数据库中,我们可以知道,数据从磁盘中要比从缓存中读取数据的时间要慢的多的多,还可以知道,同样的一个sql语句,执行的效率也不一样,这是 ...

  6. POJ 1845 (洛谷 :题目待添加)Sumdiv

    约数和 题目描述 给出a和b求a^b的约数和. 输入格式: 一行两个数a,b. 输出格式: 一个数表示结果对 9901 的模. Input 2 3 Output 15 SB的思路: 这是一道典型的数论 ...

  7. 洛谷 P1858 多人背包 DP

    目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例 输出样例 说明 思路 AC代码 题面 题目链接 洛谷 P1858 多人背包 题目描述 求01背包前k优解的价值 ...

  8. golang的包导入import

    import别名/点下划线(1)import关键字的作用:作用是导入该go源文件所依赖的package包.用在go源文件中,紧接在pakage后面的部分.(2)只要在源文件中用到了的package包就 ...

  9. 阿里云发布SaaS生态战略,成就亿级营收独角兽

    7月26日,在上海举办的阿里云合作伙伴峰会上,阿里云正式发布SaaS生态战略,计划用阿里云的品牌.渠道.资本.方法论.技术加持伙伴,成就亿级营收独角兽. 该生态战略计划招募10家一级SaaS合作伙伴, ...

  10. 【机器学习PAI实战】—— 玩转人工智能之美食推荐

    前言 在生活中,我们经常给朋友推荐一些自己喜欢的东西,也时常接受别人的推荐.怎么能保证推荐的电影或者美食就是朋友喜欢的呢?一般来说,你们两个人经常对同一个电影或者美食感兴趣,那么你喜欢的东西就很大程度 ...