HDU 5036 Explosion (傳遞閉包+bitset優化)
阿新 • • 發佈:2019-03-07
就是 $1 3-0 () case ans ffffff reset ons
因為許多門和他們之後的鑰匙可能形成閉包的關系,所以,對於所有的閉包而言,只需要炸毀其中的一個門,就可以用其後面的鑰匙打開閉包中至少一扇另外的門,一次類推。所以,假設閉包中包含$num$扇門,用炸彈打開閉包中任意一扇門的概率就為:$1/num$(因為炸毀每個閉包的概率為1,即每個閉包必然需要一枚炸彈)。所有點的概率相加,得到的最終答案就是所需炸彈的數量。但是,由於本題的$n$給到了$10^3$,單純的Floyed復雜度為$O(n^3)$,所以這裏用到了bitset來優化常數。
<題目鏈接>
題目大意:
一個人要打開或者用炸彈砸開所有的門,每個門後面有一些鑰匙,一個鑰匙對應一個門,告訴每個門裏面有哪些門的鑰匙。如果要打開所有的門,問需要用的炸彈數量為多少。 解題分析:因為許多門和他們之後的鑰匙可能形成閉包的關系,所以,對於所有的閉包而言,只需要炸毀其中的一個門,就可以用其後面的鑰匙打開閉包中至少一扇另外的門,一次類推。所以,假設閉包中包含$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];2019-03-06for(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(); } }
HDU 5036 Explosion (傳遞閉包+bitset優化)