P1273 有线电视网

xiaoxiao2021-02-28  134

//P1273 有线电视网 //花了些时间,弄明白了样例的输入输出 //如何转化为算法,还没有眉目 //http://blog.csdn.net/hehe_54321/article/details/75368187此文代码写得不错 //ans[i][j]表示第i个结点以下共j个用户观看时最大的赚钱量    //(仍然没有想到)ans[u][i]=max{ans[u][i-j]+ans[v][j]-w}   //具体解释:   /* ans[i][j][k]表示第i个结点以下前k个子结点中有j个用户观看时最大的赚钱量 ye[v]为v及以下叶节点数量 则对于边(u,v,w),ans[i][j][k]=max{ans[i][j-p][k-1]+ans[v][p][ye[v]]-w}(0<=p<=j,1<=j<=Σ(t属于前k个子结点的编号)ye[t]) 省去k一维,则需要j从大到小循环: ans[i][j]=max{ans[i][j-p]+ans[v][p]-w}(0<=p<=j,1<=j<=Σ(t属于前k个子结点)ye[t]) */ /* f(i, j),表示子树i转播给j个用户的最大收益值 这题可以看作是树上的分组背包,每个子树看作是一组物品,这一组物品可以取1个,2个...j个 然后就是套用分组背包的算法了 */    //程序有两个地方比较难理解: //1、如何保证在取数过程中,叶结点无重复,如f[i][i-j]中的叶结点 f[v][j]中的叶结点不重复 //2、for(i=ye[u];i>0;i--)正确 for(i=1;i<=ye[u];i++)错误

//针对样例1,列出动态规划过程,能说明上述问题

//for(i=ye[u];i>0;i--)正确 过程如下:

f[1][1]=max(f[1][1],f[1][1]+f[5][0]-3) f[1][1]=max(f[1][1],f[1][0]+f[5][1]-3)    1->5 取一个 最大值 f[2][1]=max(f[2][1],f[2][1]+f[4][0]-3) f[2][1]=max(f[2][1],f[2][0]+f[4][1]-3)    2->4 取一个 最大值 f[2][2]=max(f[2][2],f[2][2]+f[3][0]-2) f[2][2]=max(f[2][2],f[2][1]+f[3][1]-2) f[2][2]=max(f[2][2],f[2][0]+f[3][2]-2)    2->4 2->3 取两个 最大值 f[2][1]=max(f[2][1],f[2][1]+f[3][0]-2) f[2][1]=max(f[2][1],f[2][0]+f[3][1]-2)    2->4 2->3 取一个 最大值 f[1][3]=max(f[1][3],f[1][3]+f[2][0]-2) f[1][3]=max(f[1][3],f[1][2]+f[2][1]-2) f[1][3]=max(f[1][3],f[1][1]+f[2][2]-2) f[1][3]=max(f[1][3],f[1][0]+f[2][3]-2)    1->5 1->4 1->3 取三个 最大值 f[1][2]=max(f[1][2],f[1][2]+f[2][0]-2) f[1][2]=max(f[1][2],f[1][1]+f[2][1]-2) f[1][2]=max(f[1][2],f[1][0]+f[2][2]-2)    1->5 1->4 1->3 取两个 最大值 f[1][1]=max(f[1][1],f[1][1]+f[2][0]-2) f[1][1]=max(f[1][1],f[1][0]+f[2][1]-2)    1->5 1->4 1->3 取一个 最大值 //for(i=1;i<=ye[u];i++)错误 过程如下:

f[1][1]=max(f[1][1],f[1][1]+f[5][0]-3) f[1][1]=max(f[1][1],f[1][0]+f[5][1]-3)    1->5 取一个 最大值 f[2][1]=max(f[2][1],f[2][1]+f[4][0]-3) f[2][1]=max(f[2][1],f[2][0]+f[4][1]-3)    2->4 取一个 最大值 f[2][1]=max(f[2][1],f[2][1]+f[3][0]-2) f[2][1]=max(f[2][1],f[2][0]+f[3][1]-2)    2->4 2->3 取一个 最大值 f[2][2]=max(f[2][2],f[2][2]+f[3][0]-2) f[2][2]=max(f[2][2],f[2][1]+f[3][1]-2) f[2][2]=max(f[2][2],f[2][0]+f[3][2]-2)    2->4 2->3 取两个 最大值 f[1][1]=max(f[1][1],f[1][1]+f[2][0]-2) f[1][1]=max(f[1][1],f[1][0]+f[2][1]-2)    1->5 1->4 1->3 取一个 最大值 f[1][2]=max(f[1][2],f[1][2]+f[2][0]-2) f[1][2]=max(f[1][2],f[1][1]+f[2][1]-2)     //此处有问题 f[1][1]可能是1->4 故f[1][2]有可能取成 1->4 1->4 错误从此处开始 f[1][2]=max(f[1][2],f[1][0]+f[2][2]-2)    1->5 1->4 1->3 取两个 最大值 f[1][3]=max(f[1][3],f[1][3]+f[2][0]-2) f[1][3]=max(f[1][3],f[1][2]+f[2][1]-2) f[1][3]=max(f[1][3],f[1][1]+f[2][2]-2) f[1][3]=max(f[1][3],f[1][0]+f[2][3]-2)    1->5 1->4 1->3 取三个 最大值     //分析的过程中,同时将上述的两个顾虑问题解决。

//2017-9-1 17:55 AC #include <stdio.h> #include <string.h> #define INF 999999 int head[3100],cnt=0,ye[3100],f[3100][3100];//f[i][j] i节点及以下共j个用户的最大收益 因收益有正有负,故初始化为绝对值比较大的负数 struct node{//邻接表     int to,next,c; }e[3100];//有向图 void addedge(int u,int v,int c){     cnt++,e[cnt].to=v,e[cnt].c=c,e[cnt].next=head[u],head[u]=cnt; } int max(int a,int b){     return a>b?a:b; } void dfs(int u){     int v,b,i,j,c;//b边     b=head[u];     while(b){         v=e[b].to,c=e[b].c;         dfs(v);         ye[u]+=ye[v];         for(i=ye[u];i>=1;i--)             for(j=0;j<=i;j++)                 f[u][i]=max(f[u][i],f[u][i-j]+f[v][j]-c);//1 此处写成 f[u][j]=max(f[i][j],f[u][i-j]+f[v][j]-c);         b=e[b].next;     } } int main(){     int n,m,i,j,p,k,a,c,ans=-INF;     memset(head,0,sizeof(head));     memset(ye,0,sizeof(ye));     scanf("%d%d",&n,&m);     for(i=1;i<=n;i++)         for(j=1;j<=m;j++)             f[i][j]=-INF;     for(i=1;i<=n;i++)         f[i][0]=0;//取0个,值为0     p=n-m;     for(i=1;i<=p;i++){         scanf("%d",&k);         for(j=1;j<=k;j++){             scanf("%d%d",&a,&c);             addedge(i,a,c);         }     }     for(i=p+1;i<=n;i++){         scanf("%d",&c);         f[i][1]=c,ye[i]=1;     }     dfs(1);     for(i=ye[1];i>=1;i--){         ans=i;         if(f[1][i]>=0)break;     }     printf("%d\n",ans);     return 0; }

转载请注明原文地址: https://www.6miu.com/read-85758.html

最新回复(0)