今天狀態好差啊~ 寫一發題解壓壓驚,非常感謝左側 ← HSZX TS_Hugh 大佬教我樹形DP..
題面
解題思路
題中的依賴關係顯然是一種樹的結構,因爲n比較小而b巨大無比,DP時可以把n設爲狀態的一維。令
遞歸處理每棵子樹,然後依次把當前子樹的信息與根節點當前記錄的信息合併。令tmp[i]表示在根節點x及x的前k-1棵子樹中購買i個物品的最小代價,
因爲優惠券的使用有依賴關係,所以f[x]的合併稍微特殊一點,先不考慮根節點的貢獻,在所有子樹合併完成之後直接把根節點的那個物品加入到f[x]數組的所有選取方案中。這樣就實現了,讓f[x]中的所有方案都必須購買根節點x所表示的物品。
這個方法好像看起來是
代碼
此代碼常數巨大無比,因爲我最開始爆了int
,發現要開long long
,懶得改了,直接寫了#define ing long long
。。
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#include<vector>
#include<cstring>
using namespace std;
const int maxn=5000+10;
typedef long long LLint;
#define int long long
LLint f[maxn][maxn],g[maxn][maxn],n,b;
vector<int>son[maxn];int c[maxn],d[maxn],siz[maxn];
inline int geti(){
int ans=0,flag=0;char c=getchar();
while(!isdigit(c)){flag|=c=='-';c=getchar();}
while( isdigit(c)){ans=ans*10+c-'0';c=getchar();}
return flag?-ans:ans;
}
void inline puti(int x){
if(x<0)x=-x,putchar('-');
if(x>9)puti(x/10); putchar(x%10+'0');
}
LLint tmp[maxn];
void sol(int x){
g[x][0]=0;g[x][1]=c[x];siz[x]=1;//not use
f[x][0]=0;//use
for(int i=0;i<son[x].size();i++){//考慮所有子樹
int u=son[x][i];sol(u);
memcpy(tmp,g[x],(siz[x]+1)*sizeof(LLint));//複製數據,防止重複影響
for(int v=0;v<=siz[x];v++)
for(int j=0;j<=siz[u];j++)
g[x][v+j]=min(g[x][v+j],tmp[v]+g[u][j]);
memcpy(tmp,f[x],(siz[x]+1)*sizeof(LLint));//複製數據,同理
for(int v=0;v<siz[x];v++)
for(int j=0;j<=siz[u];j++)
f[x][v+j]=min(f[x][v+j],
tmp[v]+min(f[u][j],g[u][j]));
siz[x]+=siz[u];//表示當前已經和根節點合併的連通塊大小
}
for(int i=siz[x];i>=1;i--){//把x加到所有方案中
f[x][i]=f[x][i-1]+c[x]-d[x];
}
}
signed main(){
freopen("supermarket.in","r",stdin);
freopen("supermarket.out","w",stdout);
memset(g,0x7f,sizeof(g));
memset(f,0x7f,sizeof(f));
n=geti();b=geti();
c[1]=geti();d[1]=geti();
for(int i=2;i<=n;i++){
c[i]=geti();d[i]=geti();
int x=geti();
son[x].push_back(i);
}
sol(1);//dfs
for(int i=n;i>=0;i--){//O(n)掃一遍即可
int cost=min(f[1][i],g[1][i]);
if(cost<=b){
printf("%d\n",i);
break;
}
}
return 0;
}
[2017.12.28] 來自TS_Hugh 大佬的卡常神技
char xB[(1<<15)+10],*xS=xB,*xT=xB;
#define gtc (xS==xT&&(xT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xT)?0:*xS++)
本機實測,讀入