題解 $UVA$ 11825【$Hackers$' $Crackdown$】
本題的數學模型是:把\(\mathcal{n}\)個集合\(\mathcal{P1,P2,...,Pn}\)分成盡量多組,使得每組中所以集合的並集等於全集。這裏集合\(\mathcal{Pi}\)就是計算機\(\mathcal{i}\)及其相鄰計算機的集合,每組對應於題目中的一項服務。
註意到\(\mathcal{n}\)很小,可以套用《算法競賽》裏面提到的二進制法表示這些集合,即在代碼中,
每個集合\(\mathcal{Pi}\)實際上是一個非負整數。輸入部分代碼如下:
for(int i=0;i<n;i++) { int m,x; scanf("%d",&m); P[i]=1<<i; while(m--) { scanf("%d",&x); P[i]|=(1<<x); } }
為了方便,窩萌用\(\mathcal{cover(S)}\)表示若幹\(\\mathcal{Pi}\)的並集(二進制表示),即這些\(\mathcal{Pi}\)在數值上的“按位或”。
for{int S=0;S<(1<<n);S++)
{
cover[S]=0;
for(int i=0;i<n;i++)
if(S & (1<<i)) cover[S]=P[i];
}
不難想到這樣的動態規劃:用\(\mathcal{f(S)}\)表示子集\(S\)最多可以分成多少組,則
\(\mathcal{f(S)=max(f(S-S0)|S0}\)
\(\text{(劃重點!!)}\)\(\text{這裏有一個重要的技巧:枚舉}\)\(\mathcal{S}\)\(\text{的子集}\)\(\mathcal{S0}\)。
詳見下面代碼:
f[0]=0; int All=(1<<n)-1; for(int S=1;S<(1<<n);S++ { f[S]=0; for(int S0=S;S0;S0=(S0-1)&S) if(cover[S0]==All f[S]=max(f[S],f[S^S0]+1); } printf("Case %d: %d\n",++kase,f[ALl]);
如何分析上述算法的時間復雜度呢\(qwq\)?它等於全集\(\mathcal{(1,2,3,...,n)}\)的所有子集的子集個數之和,也可以令
\(\mathcal{c(S)}\)表示集S的子集的個數(它等於\(\text{2}\)\(\mathcal{^|}\)\(\mathcal{^s}\)\(\mathcal{^|}\)),則本題的時間復雜度為
\(\mathcal{sum(c(S)|S0}\)\(\text{是(1,2,3,...,n)的子集)}\)。
註意到元素個數相同的集合,其子集個數也相同,窩萌可以按照元素個數“合並同類元素項”。元素個數為\(k\)的集合有
\(\mathcal{C(n,k)}\)個,其中每個集合有\(\text{2}\)\(\mathcal{^k}\)個子集(高一\(\mathcal{New}\) \(\mathcal{knowledge}\)),
因此本題的時間復雜度為
\(\mathcal{sum(C(n,k)}\)\(\text{2}\)\(\mathcal{^k}\)\(\mathcal{=}\)\(\text{(2+1)}\)\(\mathcal{^n}\)\(\mathcal{=}\)\(\text{3}\)\(\mathcal{^n}\)其中第一個等號得到的用到了二項式定理(不過是反著用的\(QwQ\))
本題比較抽象,大家花點時間仔細想明白哦~~
題解 $UVA$ 11825【$Hackers$' $Crackdown$】