1. 程式人生 > >題解 $UVA$ 11825【$Hackers$' $Crackdown$】

題解 $UVA$ 11825【$Hackers$' $Crackdown$】

lin 其中 print %d 動態規劃 over 代碼 集合 相同

本題的數學模型是:把\(\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{是S的子集,}\)\(\mathcal{cover[So]}\)\(\text{等於全集)}\)\(\text{+1}\)


\(\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$】