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\n",ans);
    }
    return 0;
}

  

HDU 4921 Map DFS+状态压缩+乘法计数

时间: 2024-10-24 09:11:45

HDU 4921 Map DFS+状态压缩+乘法计数的相关文章

hdu 4352 数位dp + 状态压缩

XHXJ's LIS Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2265    Accepted Submission(s): 927 Problem Description #define xhxj (Xin Hang senior sister(学姐)) If you do not know xhxj, then careful

HDU 4921 Map

题意: 给n个节点  他们形成了最多10条链  每条最多1000的长度  每个节点有个val  你可以选择任意位置截断链  断点前的所有节点被你获得  通过题中计算公式得出你的val  问  通过随机截断  获得val的期望是多少 思路: 期望=所有方案val的和/方案数 这里明显有分层的现象  而且每层最多10个元素  因此想到状压  那么我们只要逐层统计  每层计算一下能对"所有方案val的和"产生多少贡献即可  方案数可以直接算出来  计算方法如下 对于方案数  它就等于 (am

HDU 1885 Key Task 状态压缩+搜索

点击打开链接 Key Task Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1176    Accepted Submission(s): 462 Problem Description The Czech Technical University is rather old - you already know that it c

hdu 4778 Rabbit Kingdom(状态压缩)

题目链接:hdu 4778 Rabbit Kingdom 题目大意:Alice和Bob玩游戏,有一个炉子,可以将S个相同颜色的宝石换成一个魔法石,现在有B个包,每个包里有若干个宝石,给出宝石的颜色.现在由Alice开始,两人轮流选取一个包的宝石放入炉中,每当获得一个魔法石时,可以额外获得一次机会再选一个包放入.两人均按照自己的最优策略,问说最后Alice的魔法石-Bob的魔法石是多少. 解题思路:状态压缩,221,对于每次移动到下一个状态,如果获得的魔法石g非零,则说明下一个状态还是自己在取,则

hdu 3217 Health(状态压缩DP)

Health Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 527    Accepted Submission(s): 145 Problem Description Unfortunately YY gets ill, but he does not want to go to hospital. His girlfriend LM

hdu 4856 Tunnels(bfs+状态压缩)

题目链接:hdu 4856 Tunnels 题目大意:给定一张图,图上有M个管道,管道给定入口和出口,单向,现在有人想要体验下这M个管道,问最短需要移动的距离,起点未定. 解题思路:首先用bfs处理出两两管道之间移动的距离,然后后用状态压缩求出最短代价,dp[i][j],i表示的已经走过的管道,j是当前所在的管道. #include <cstdio> #include <cstring> #include <queue> #include <algorithm&g

HDU 1557 权利指数 状态压缩 暴力

HDU 1557 权利指数 状态压缩 暴力 ACM 题目地址:HDU 1557 权利指数 题意: 中文题,不解释. 分析: 枚举所有集合,计算集合中的和,判断集合里面的团体是否为关键团队. 代码: /* * Author: illuz <iilluzen[at]gmail.com> * File: 1557.cpp * Create Date: 2014-06-28 14:47:58 * Descripton: brute force/ set */ #include <cstdio&g

hdu 4057 AC自动机+状态压缩dp

http://acm.hdu.edu.cn/showproblem.php?pid=4057 Problem Description Dr. X is a biologist, who likes rabbits very much and can do everything for them. 2012 is coming, and Dr. X wants to take some rabbits to Noah's Ark, or there are no rabbits any more.

hdu 5067 网络赛 状态压缩 或dfs

题意是给你n*m的方格 里面有最多10个格子有数  问你最少走多少步能将所有的数字移到左上角    能无限装下数字 这里介绍两种做法  dfs和状态压缩dp 1   dfs 由于每个数字之间是一定可以到达的  所有只用考虑走有数字的情况   最多10!种情况  找到做小的就行   果断的深搜       注意下优化 #include<stdio.h> #include<string.h> #include<iostream> using namespace std; s