cf 815C Karen and Supermarket 树形dp

来源:互联网 发布:照片打分软件 编辑:程序博客网 时间:2024/05/01 17:21

题目链接点这里

把他看成一棵树,dp[i][j][k]是对于j点用不用优惠券(i)已选k个的最小花费。。。很明显对子树做一个分组背包即可。然而乍一看分组背包的复杂度不是n(n个点)*n*n(dp复杂度)是n^3次方吗?

这里有2种dp方式1.dfs过程中处理u时初始siz[u]=1,搞完u的一棵子树v,花O(siz[u]*siz[v])dp,然后在siz[u]+=siz[v],继续其他子树 2.先siz[u]+=siz[v],然后再花O(siz[u]*siz[v])dp。 

第一种是O(n^2)的,因为这就相当于求了一次任意两点的lca,

第二种在树是一条链的时候,是n^3的

#include<iostream>#include<cstdio>#include<math.h>#include<algorithm>#include<map>#include<set>#include<bitset>#include<unordered_map>#include<stack>#include<queue>#include<string.h>#include<cstring>#include<vector>#include<time.h>#include<stdlib.h>using namespace std;#define INF 0x3f3f3f3f#define INFLL 0x3f3f3f3f3f3f3f3f#define FIN freopen("input.txt","r",stdin)#define mem(x,y) memset(x,y,sizeof(x))typedef unsigned long long ULL;typedef long long LL;#define fuck(x) cout<<"q"<<endl;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1typedef pair<pair<int,int>,int> PIII;typedef pair<int,int> PII;const double eps=1e-8;const int P=1e9+7;const int  MX=5000+5;//最大范围int n,b,dp[2][MX][MX];int c[MX],d[MX];struct Edge{    int nxt,to;} E[MX];int head[MX],edge_cnt;void edge_init(){    mem(head,-1);    edge_cnt=0;}void edge_add(int u,int v){    E[edge_cnt].nxt=head[u];    E[edge_cnt].to=v;    head[u]=edge_cnt++;}int sz[MX];void dfs(int u){    sz[u]=1;    dp[0][u][0]=0;    dp[0][u][1]=c[u];    dp[1][u][1]=c[u]-d[u];    for(int i=head[u]; ~i; i=E[i].nxt)    {        int v=E[i].to;        dfs(v);        for(int j=sz[u]; j>=0; j--)        {            for(int k=1; k<=sz[v]; k++)            {                dp[0][u][j+k]=min(dp[0][u][j+k],dp[0][u][j]+dp[0][v][k]);                dp[1][u][j+k]=min(dp[1][u][j+k],dp[1][u][j]+dp[0][v][k]);                dp[1][u][j+k]=min(dp[1][u][j+k],dp[1][u][j]+dp[1][v][k]);            }        }        sz[u]+=sz[v];    }}int main(){    FIN;    while(cin>>n>>b)    {        mem(dp,0x3f);        edge_init();        for(int i=1; i<=n; i++)        {            int x;            scanf("%d%d",&c[i],&d[i]);            if(i!=1)            {                scanf("%d",&x);                edge_add(x,i);            }        }        dfs(1);        int ans=0;        for(int i=n; i>=0; i--)            if(dp[1][1][i]<=b||dp[0][1][i]<=b)            {                ans=i;                break;            }        cout<<ans<<endl;    }    return 0;}


原创粉丝点击