首页 > 代码库 > 洛谷 P1273 有线电视网(dp)

洛谷 P1273 有线电视网(dp)

/*想了半天没想出状态 自己还是太弱了 QAQ题目问的是最多供给多少户 一般想法是把这个值定义为状态量没想出来QAQ....看了看题解的状态 很机智.... f[i][j]表示i的子树 选了j个叶子的最大收益这样 不亏本就是收益>=0 转移的话 先搜一下这个子树有几个叶子 然后枚举儿子 枚举当前儿子分几个叶子 这里的枚举顺序有套路从大到小枚举i分几个 从小到大枚举j分几个这样可以避免 重复选择 注意初始化 */#include<iostream>#include<cstdio>#include<cstring>#define maxn 3010using namespace std;int n,m,p,head[maxn],num,f[maxn][maxn],ans,c[maxn];struct node{    int v,t,pre;}e[maxn];void Add(int from,int to,int dis){    num++;e[num].v=to;    e[num].t=dis;    e[num].pre=head[from];    head[from]=num; }int Dfs(int u){    if(u>p){        f[u][1]=c[u];        return 1;    }    int s=0;    for(int i=head[u];i;i=e[i].pre){        int v=e[i].v;        int x=Dfs(v);s+=x;        for(int j=s;j>=1;j--)            for(int k=1;k<=x;k++)                f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]-e[i].t);    }    return s;}int main(){    scanf("%d%d",&n,&m);p=n-m;    for(int i=1;i<=p;i++){        int x,y,z;        scanf("%d",&x);        for(int j=1;j<=x;j++){            scanf("%d%d",&y,&z);            Add(i,y,z);        }    }    for(int i=p+1;i<=n;i++)        scanf("%d",&c[i]);    memset(f,-127/3,sizeof(f));    for(int i=1;i<=n;i++)        f[i][0]=0;    Dfs(1);    for(int i=0;i<=m;i++)        if(f[1][i]>=0)ans=max(ans,i);    printf("%d\n",ans);    return 0;} 

 

洛谷 P1273 有线电视网(dp)