poj2057-树状dp

来源:互联网 发布:如何学好高中数学知乎 编辑:程序博客网 时间:2024/05/16 12:33

第一次写树状dp,完全没什么概念,而且这题看了感觉好复杂,看了好几个人的解题报告,想了一段时间才想明白那个转移方程的含义,这几份报告都很详细,最后按http://blog.sina.com.cn/s/blog_5f5353cc0100hd08.html的思路写的,由于第一次写,所以加了很多注释,也仿照了其他博主的代码,越写越感觉到树状dp的神奇,不过要能独自相处转移方程,确实还有待提升,加油!

//ljr 2014-1-22//poj2057 树状dp的运用#include<cstdio>#include<algorithm>#include<vector>using namespace std;//leaves[i]以i为根节点的叶子数,//fail[i]以i为根在子树中找不到房子所走步数//success[i]以i为根在子树中找到房子所走的步数//worm[i],i处是否存在虫子int leaves[1005],fail[1005],success[1005],worm[1005],n,node;vector<int>son[1005];//存每个结点的儿子char ch;bool cmp(int u,int v){     return (fail[u]+2)*leaves[v]<(fail[v]+2)*leaves[u];//这个是化简以后的式子}//假设x为u,v的父亲//化简过程,ans1=(fail[x]+1)*leaves[u]+success[u]+(fail[x]+fail[u]+1)*leaves[v]+success[v];//         ans2=(fail[x]+1)*leaves[v]+success[v]+(fail[x]+fail[v]+1)*leaves[u]+success[u];//ans1-ans2=(fail[u]+2)*leaves[v]-(fail[v]+2)*leaves[u];void solve(int x){      if(son[x].size()==0){//已经是树叶结点,处理返回            leaves[x]=1;  success[x]=0; fail[x]=0;      }      else{//非叶子结点            for(int i=0; i<son[x].size(); i++)                solve(son[x][i]);//往上传递            for(int i=0; i<son[x].size(); i++){//根节点的儿子们信息已经更新完了,来更新它自己                leaves[x]+=leaves[son[x][i]];//统计叶子结点个数即是儿子们的叶子数之和                if(worm[x]==0)fail[x]+=fail[son[x][i]]+2;//在该点无虫的情况下,这里每次多+2是因为从根到儿子i再回到根,多增两次路径            }            //寻找失败的时候是不论先走哪个儿子结果都是一样的,但寻找成功时却不同,有着具体的顺序,这也是本题的关键            //通过之前讨论得出的更新方程,进行一个贪心排序,然后遍历每一点找到房子时的情况            int temp[10];            for(int i=0; i<son[x].size(); i++)                temp[i]=son[x][i];            sort(temp,temp+son[x].size(),cmp);            int j=0;//用j来统计在根节点子树中找不到房子所走步数            for(int i=0; i<son[x].size(); i++){                 success[x]+=(j+1)*leaves[temp[i]]+success[temp[i]];//进行更新                 j+=fail[temp[i]]+2;//j是需要时时更新的            }      }}int main(){      while(scanf("%d",&n)==1&&n){           for(int i=1; i<=n; i++){               son[i].clear();               worm[i]=0;               success[i]=0;               leaves[i]=0;               fail[i]=0;           }           for(int i=1; i<=n; i++){               scanf("%d %c",&node,&ch);               if(node!=-1)son[node].push_back(i);               if(ch=='Y')worm[i]=1;           }           solve(1);//树状dp,采用递归来更新,并且要从树叶更新到树根的更新           printf("%.4f\n",success[1]*1.0/leaves[1]);      }      return 0;}


0 0
原创粉丝点击