zoukankan      html  css  js  c++  java
  • HDU 4921 Map DFS+状态压缩+乘法计数

    算最多十条链,能截取某前缀段,每种方案都可以算出一个权值,每种方案的概率都是总数分之一,问最后能构成的所有可能方案数。

    对计数原理不太敏感,知道是DFS先把链求出来,但是想怎么统计方案的时候想了好久,其实因为只能取某个链的前缀,所以直接取链长加+1 然后相乘即可,当然因为会出现都是空的那种情况,要去掉,全部乘完之后,要-1

    然后就是算权值了,权值等于当前加进来的点的总和 以及 等级相同的点的加成,并不是特别好算,这时候考虑每个状态下的点对全局的贡献,对,就是这个思想,用状态压缩来表示状态,然后这个状态占用的所有情况,又可以用乘法原理乘出来。然后对这个状态算出权值之后,乘以所有的占用情况即可

    下标是从0开始的,注意

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    using namespace std;
    const int N = 10010;
    int u[N],v[N],ft[N],nt[N];
    int ind[N],deep[N],val[N],vis[N];
    int n,m,cnt;
    vector <int> ve[20];
    int dir[20],sz[1100],cur;
    void init()
    {
        for (int i=0;i<=n;i++){
            ft[i]=-1;
            ind[i]=0;
            vis[i]=0;
        }
        cnt=0;
        cur=0;
        for (int i=0;i<20;i++){
            ve[i].clear();
        }
        for (int i=0;i<1100;i++) sz[i]=0;
    }
    void add(int a,int b)
    {
        u[cnt]=a;
        v[cnt]=b;
        nt[cnt]=ft[a];
        ft[a]=cnt++;
    }
    void dfs(int x)
    {
        if (vis[x]) return;
        vis[x]=1;
        for (int i=ft[x];i!=-1;i=nt[i]){
            int vx=v[i];
            if (vis[vx]) continue;
            ve[cur-1].push_back(vx);
            int len=ve[cur-1].size();
            sz[len-1]++;
            dfs(vx);
        }
    }
    int main()
    {
        int t,a,b;
        scanf("%d",&t);
        while (t--)
        {
            scanf("%d%d",&n,&m);
            init();
            for (int i=0;i<n;i++){
                scanf("%d",&val[i]);
            }
            while (m--)
            {
                scanf("%d%d",&a,&b);
                add(a,b);
                ind[b]++;
            }
            for (int i=0;i<n;i++){
                if (vis[i]==0 && ind[i]==0){
                    dir[cur++]=i;
                    ve[cur-1].push_back(i);
                    dfs(i);
                    sz[0]++;
                }
            }
            double tot=1;
            int maxn=0;
            for (int i=0;i<cur;i++){
                int tmp=ve[i].size();
                maxn=tmp>maxn?tmp:maxn;
                tot*=(double)(tmp+1);
            }
            tot-=1;
            double ans=0,sum=0;
            for (int i=0;i<maxn;i++){
               // cout<<"Test "<<i<<endl;
                for (int j=1;j<(1<<cur);j++){
                    //cout<<"sta "<<j<<endl;
                    sum=0;
                    int tmp=0;
                    double calc=1.0;
                    for (int k=0;k<cur;k++){
                        int r=ve[k].size();
                        bool flag=((1<<k)&j);
                        if (r<=i && flag){
                            sum=0;
                            break;
                        }
                        if (i<r && flag){
                            sum+=(double)val[ve[k][i]];
                            tmp++;
                            calc*=(double)(r-i);
                        }
                        else
                        {
                            calc*=(min(r,i)+1)*1.0;
                        }
                    }
                    //cout<<"calc "<<calc<<endl;
                    //cout<<"sum "<<sum<<endl;
                    ans+=sum*calc;
                    if (tmp>1) ans+=calc*(double)tmp/(double)sz[i]*sum;
                   // cout<<"ans "<<ans<<endl;
                }
            }
            //cout<<"cur "<<cur<<endl;
            //cout<<ans<<" "<<tot<<endl;
            ans=ans/tot;
            printf("%.3lf
    ",ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    The Android ION memory allocator
    ffmpeg 从mp4上提取H264的nalu
    annexb模式
    算法优化:rgb向yuv的转化最优算法
    Android平台上PMEM的使用及Platform设备注册(二)
    Android平台上PMEM的使用及Platform设备注册(一)
    ffmpeg教程
    视频编解码学习之四:视频处理及编码标准
    深入浅出:了解jsonp跨域的九种方式
    前端小知识集锦
  • 原文地址:https://www.cnblogs.com/kkrisen/p/3917572.html
Copyright © 2011-2022 走看看