HDU 5036 Explosion 2014 北京网络赛E题

54 篇文章 0 订阅
19 篇文章 0 订阅

点击打开链接

概率题,这是我第二次接触概率题目。上次是另一个比赛中的walk

貌似概率题经常考察。

题意:有N间房子,每个房子有一扇门,且其中会放有若干其他房间钥匙。此时若无法打开可以用炸弹炸开。求使用炸弹的期望。


看到这个题目,若傻傻的用搜索就TLE。抽象思考下,打开特定一扇门,至多用一次炸弹。因此本题是求每个点用炸弹打开概率的和。

对于每个点V,其打开概率就是1/S(S是u->v)联通的数量,即求这个图的传递闭包。 1*1/S为该点的期望。

再使用bitset对其优化


这里使用的闭包传递

        for(i=0;i<n;i++)
            for(j=0;j<n;j++)
            {
                if(bt[j][i]) bt[j]|=bt[i];
            }
注意bt[j][i]  不同于之前,这里是有向图。可以这样理解:j点到i点有路,那么i点可到达的点,j点也可以通过走i到达。但是反过来不可以。

这里求的是一个点有多少个点可以到达,所以bt[j]|=bt[i] 就计算出了可以走到bt[j]的点数

#include <stdio.h>
#include <string.h>
#include <bitset>
#include <iostream>
#define inf 0x3fffffff
const int maxn=1010;
typedef unsigned __int64 ull;
using namespace std;

bitset<1010>bt[1010];
int main()
{
    int T;
    int n,m,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        int i,j,k;
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            bt[i].reset();
            bt[i][i]=1;
        }
        for(i=0;i<n;i++)
        {
            scanf("%d",&k);
            for(j=0;j<k;j++)
            {
                int tt;
                scanf("%d",&tt);
                bt[i][tt-1]=1;
            }
        }
        for(i=0;i<n;i++)
            for(j=0;j<n;j++)
            {
                if(bt[j][i]) bt[j]|=bt[i];
            }
        double ans=0;
        for(i=0;i<n;i++)
        {
            k=0;
            for(j=0;j<n;j++)
            {
                if(bt[j][i]) k++;
            }
            ans+=1.0/k;
        }
        printf("Case #%d: %.5f\n",cas++,ans);

    }
    return 0;
}


顺带:bitset的用法

(bitset优化的 bitset 类简化了位集的处理,有些程序要使用二进制位的有序集来保存一组项或条件的标志位,可以考虑使用bitset。

需要的文件:

#include <bitset>

Using std::bitset

l         bitset 对象的定义和初始化

定义bitset时,要明确bitset有多少位:

bitset<32> bitvec     // 32位二进制,初始化为0,0~31

用unsigned 值初始化bitset 对象:

当用unsigned 值初始化bitset 对象时,该值将转化为二进制的位模式。如果bitset类型长度大于 unsigned值的二进制位数,则其余的高阶位将置为0;如果bitset 类型长度小于unsigned 值的二进制位数,则只使用unsigned值中的低阶位,超过bitset类型长度的高阶位将被丢弃。

bitset<16> bit ( 0xFFFF )              // 0~15位都置1

bitset<32> bit ( 0xFFFF )              // 0~15位置1,16~31位置0

用 string 对象初始化bitset对象

string strval ( “1100” )

bitset<32> bit ( strval )

注意:从string对象读入位集的顺序是从右向左。即反向转化:string对象最右边的字符用来初始化bitset对象的低阶位(即下标为0的位)。

bit 的位模式中第2和3位置为1,其余位置都为0。如果string对象的字符个数小于bitset类型的长度,则高阶位将置为0。

       不一定要把整个string对象都作为bitset的初始值,可以只用某个子串作为初始值:

string str ( “111111111100000000011011” )

bitset<32> bit ( str , 5 , 4 )

l         bitset的成员函数

any()             是否存在位置为1的二进制位

none()          不存在置为1的二进制位?

count()         置为1的二进制位的个数

size()            总的二进制位的个数

[pos]            访问在pos处的二进制位

test(pos)     pos处的二进制位是否为1

set()             所有位都置1

set(pos)              pos处的二进制置1

reset()         所有二进制置0

reset(pos)   pos处的二进制位置0

flip()             所有位置反

flip(pos)              pos位置反

to_ulong()   返回一个 unsigned long 值

os<<b           位集输出到os流求解概率)
更多请参考:点击打开链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值