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

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

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

看到题的第一眼以为是树形背包,然后看到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. netbeans 代码自动补全设置

    编辑器-----代码完成------语言选择"JAVA"------在如图红框中输入 @ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrst ...

  2. HTTPS的实现

    1.安装专门的mod_ssl模块 [root@contos7 ~]# yum install mod_ssl Loaded plugins: fastestmirror, langpacks Load ...

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

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

  4. bzoj 4198 [Noi2015]荷马史诗——哈夫曼树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4198 学习一下哈夫曼树.https://www.cnblogs.com/Zinn/p/940 ...

  5. web前端学习(三)css学习笔记部分(8)-- SVN的介绍和应用、CSS动画效果、CSS3布局属性全接触

    15.SVN的介绍和应用 15.1.SVN的介绍和应用课程概要 将代码进行集中管理,有版本号的进行迭代,方便集体工作的build流程 15.2.SVN的介绍 SVN是Subversion的简称,是一个 ...

  6. CISC和RISC是什么?它们的特点和区别?

    CISC的英文全称为“Complex Instruction Set Computer”,即“复杂指令系统计算机”,从计算机诞生以来,人们一直沿用CISC指令集方式.早期的桌面软件是按CISC设计的, ...

  7. 【JZOJ3617】【ZJOI2014】力

    ╰( ̄▽ ̄)╭ 对于100%的数据,n≤100000;0<qi<1,000,000,000. (⊙ ▽ ⊙) 令ri=1i2, 设Fj=∑j−1i=0qi∗rj−1−i,Gj=∑j−1i= ...

  8. Haskell 学习

    truncate pi -- 表示截断, 此处结果为 3 haskell中的touple是可变的,而python中是不可变的 lines函数: lines :: String -> [Strin ...

  9. iOS从零开始 Code Review

    http://www.cocoachina.com/ios/20151117/14208.html 这篇帖子不是通篇介绍Code Review的方法论, 而是前大段记录了我们团队怎么从没有这个习惯到每 ...

  10. 洛谷P1879 玉米田

    题目描述 农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地.John打算在牧场上的某几格里种上美味的草,供他 ...