您的位置:首页 > 理论基础 > 计算机网络

HDU 5036 Explosion 2014 北京网络赛E题

2014-10-16 17:48 295 查看
点击打开链接

概率题,这是我第二次接触概率题目。上次是另一个比赛中的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流求解概率)

更多请参考:点击打开链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: