[BZOJ 4117] Weather Report
Link:
Solution:
第一次写$Huffman Tree$相关,发现就是个合并果子?
此题可以将每一种情况的概率和排列总数算出,接下来就是按照$Haffman Tree$基本构造方式操作了
注意,这里使用了分治的思想:
(1)如果排列总数大于1,先排除奇数影响,再将$P(pro,num)$变为$P(pro*2,num/2)$,
相当于将排列拆成相等的两部分再合并到一起
(2)如果排列总数等于1,再取下一个 概率最小的方式中的一个排列 合并即可
这样将排列方式不断减半、到一再合并的方法方便了概率的叠加
(Question:存疑点,为什么不能按照$pro*num$从小到大排序直接进行合并呢?)
Code:
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<double,ll> P; #define X first #define Y second const int MAXN=25; int n;ll c[MAXN][MAXN]; double A,B,C,D,pa[MAXN],pb[MAXN],pc[MAXN],pd[MAXN],res; priority_queue<P,vector<P>,greater<P> > q; int main() { c[0][0]=1; for(int i=1;i<=20;i++) { c[i][0]=1; for(int j=1;j<=20;j++) c[i][j]=c[i-1][j]+c[i-1][j-1]; } scanf("%d%lf%lf%lf%lf",&n,&A,&B,&C,&D); pa[0]=pb[0]=pc[0]=pd[0]=1.0; //预处理 for(int i=1;i<=n;i++) pa[i]=pa[i-1]*A,pb[i]=pb[i-1]*B,pc[i]=pc[i-1]*C,pd[i]=pd[i-1]*D; for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) for(int k=0;k<=n;k++) for(int l=0;l<=n;l++) if(i+j+k+l==n) q.push(P(pa[i]*pb[j]*pc[k]*pd[l],c[n][i]*c[n-i][j]*c[n-i-j][k])); while(true) { P cur=q.top();q.pop(); if(q.empty() && cur.Y==1) break; if (cur.Y>1) //拆分+合并 { if(cur.Y&1) q.push(P(cur.X,1)),cur.Y--; res+=cur.X*cur.Y; q.push(P(cur.X*2,cur.Y>>1)); } else //合并 { P t=q.top();q.pop(); res+=cur.X+t.X; q.push(P(cur.X+t.X,1)); if(t.Y>1) q.push(P(t.X,t.Y-1)); } } printf("%.6f",res); return 0; }