1. 程式人生 > >HDU 5036 Explosion (傳遞閉包+bitset優化)

HDU 5036 Explosion (傳遞閉包+bitset優化)

就是 $1 3-0 () case ans ffffff reset ons

<題目鏈接>

題目大意:

一個人要打開或者用炸彈砸開所有的門,每個門後面有一些鑰匙,一個鑰匙對應一個門,告訴每個門裏面有哪些門的鑰匙。如果要打開所有的門,問需要用的炸彈數量為多少。 解題分析:
因為許多門和他們之後的鑰匙可能形成閉包的關系,所以,對於所有的閉包而言,只需要炸毀其中的一個門,就可以用其後面的鑰匙打開閉包中至少一扇另外的門,一次類推。所以,假設閉包中包含$num$扇門,用炸彈打開閉包中任意一扇門的概率就為:$1/num$(因為炸毀每個閉包的概率為1,即每個閉包必然需要一枚炸彈)。所有點的概率相加,得到的最終答案就是所需炸彈的數量。但是,由於本題的$n$給到了$10^3$,單純的Floyed復雜度為$O(n^3)$,所以這裏用到了bitset來優化常數。
#include <bits/stdc++.h>
using namespace std;
const int N=1005;
bitset<N> b[N];
int n,ncase=0;
double ans;
void floyed(){    //floyed傳遞閉包
    ans=0.0;
    for(int j=0; j<n; j++)//對於每個房間j,枚舉i,若i可以到達j,則i可以到達j可以到達的所有房間,即傳遞閉包。
        for(int i=0; i<n; i++)
            if(b[i][j])b[i]|=b[j];
    
for(int j=0; j<n; j++){ //得到每個以j為起點的閉包的節點數量 int cnt=0; for(int i=0; i<n; i++) if(b[i][j])cnt++;//對於j,看有多少個i可以直接或間接到達,最終該房間使用炸彈的期望為1.0/cnt,也就是平均要使用1.0/cnt個才能到達i; ans=ans+(1.0/cnt); } printf("Case #%d: %.5lf\n",++ncase,ans); } int main(){ int T;scanf("
%d",&T); while(T--){ scanf("%d",&n); for(int i=0; i<n; i++){ b[i].reset(); b[i][i]=1;//一定可以到達自己所在房間。 } for(int i=0; i<n; i++){ int num;scanf("%d",&num); for(int j=0; j<num; j++){ int to;scanf("%d",&to); b[i][to-1]=1;//從房間i可以到達的房間。 } } floyed(); } }
2019-03-06

HDU 5036 Explosion (傳遞閉包+bitset優化)