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

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

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

看到题的第一眼以为是树形背包,然后看到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. 直接在安装了redis的Linux机器上操作redis数据存储类型--对Sorted-Sets操作

    一.概述: Sorted-Sets和Sets类型极为相似,它们都是字符串的集合,都不允许重复的成员出现在一个Set中.它们之间的主要差别是Sorted-Sets中的每一个成员都会有一个分数(score ...

  2. Tomcate 启动异常,java.net.BindException: Address already in use: JVM_Bind:80的解决办法

    一直用Tomcat,但是前几天突然报错:           java.net.BindException: Address already in use: JVM_Bind:80 第一反应就是80端 ...

  3. windows device recovery tool 刷机

    ch 春节期间,拿出来诺基亚1020拍照,误删软件,无法登陆微软账号,考虑刷机处理 下载windows device recovery tool,进行刷机,但是固件下载一直失败 考虑下载好固件包,ff ...

  4. update当根据条件不同时 更新同一个字段的方法 或多表插入

    1.通过存储过程 循环 传值 create or replace procedure p_u isbegin for rs in (select distinct (rks) from rkbz)lo ...

  5. 【同余最短路】【例题集合】洛谷P3403 跳楼机/P2371 墨墨的等式

    接触到的新内容,[同余最短路]. 代码很好写,但思路不好理解. 同余最短路,并不是用同余来跑最短路,而是通过同余来构造某些状态,从而达到优化时间空间复杂度的目的.往往这些状态就是最短路中的点,可以类比 ...

  6. XMLHttpRequest cannot load JSONP

    转自CSDN竹音林 1.前端JS代码 <script type="text/javascript" > $.ajax({ dataType:"JSONP&qu ...

  7. 【JZOJ5088】【GDOI2017第四轮模拟day2】最小边权和 排序+动态规划

    题面 有一张n个点m条边的有向图,每条边有一个互不相同的边权w,有q个询问,要求你从点a经过不超过c条边到点b,要求经过的边权递增并和尽量小,求出最小的边权和,如果没有合法方案则输出-1. 对于100 ...

  8. 使用 store 来优化 React 组件

    在使用 React 编写组件的时候,我们常常会碰到两个不同的组件之间需要共享状态情况,而通常的做法就是提升状态到父组件.但是这样做会有一个问题,就是尽管只有两个组件需要这个状态,但是因为把状态提到了父 ...

  9. PHP获取用户客户端真实IP的解决方案是怎样呢?

    function getIp(){if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIE ...

  10. 递归系列——树型JSON数据转换问题

    JSON数据转换方式: 1.标准结构=>简单结构 var root = { id: 'root', children: [ { id: "1", children: [ { ...