2017.07.10【NOIP提高組】模擬賽B組 創(chuàng)世紀(jì) 題解

原題:

http://172.16.0.132/senior/#contest/show/2045/2

題目描述:

上帝手中有著n種被稱作“世界元素”的東西,現(xiàn)在他要把它們中的一部分投放到一個(gè)新的空間中去以建造世界。每種世界元素都可以限制另外一種世界元素,所以說上帝希望所有被投放的世界元素都有至少一個(gè)沒有被投放的世界元素能夠限制它,這樣上帝就可以保持對(duì)世界的控制。
由于那個(gè)著名的有關(guān)于上帝能不能制造一塊連自己都不能舉起的大石頭的二律背反命題,我們知道上帝不是萬能的,而且不但不是萬能的,他甚至有事情需要找你幫忙——上帝希望知道他最多可以投放多少種世界元素,但是他只會(huì)O(2^n)級(jí)別的算法。雖然上帝擁有無限多的時(shí)間,但是他也是個(gè)急性子。你需要幫助上帝解決這個(gè)問題。

輸入:

第一行一個(gè)正整數(shù)n,表示世界元素的數(shù)目。
第二行n個(gè)正整數(shù)a_1, a_2, ..., a_n。a_i表示第i個(gè)世界元素能夠限制的世界元素的編號(hào)。

輸出:

最多可以投放的世界元素的數(shù)目。

樣例輸入:

6
2 3 1 3 6 5

樣例輸出:

3

樣例說明:

選擇2、3、5 三個(gè)世界元素即可,分別有1、4、6來限制它們。

數(shù)據(jù)范圍限制:

30%的數(shù)據(jù),n<=10。
60%的數(shù)據(jù),n<=10^5。
100%的數(shù)據(jù),a_i<=n<=10^6。

分析:

貪心。
找出所有沒有入度的點(diǎn),那么這些點(diǎn)必定不能選入集合中,我們沿著這些點(diǎn)上溯,將可以選進(jìn)集合的點(diǎn)都選進(jìn)集合。
這里“可以選進(jìn)”的定義為存在一個(gè)沒有被選進(jìn)集合的前驅(qū)。
于是環(huán)上就會(huì)有若干個(gè)由樹上決定它要選進(jìn)集合的點(diǎn)。
我們將環(huán)按照已選入集合的點(diǎn)來分裂成若干段,每一段按照原來的貪心方法來貪心即可。

貪心正確性的證明:

我們將一個(gè)點(diǎn)從“選”的狀態(tài)變成不選,顯然不會(huì)改變其前驅(qū)的狀態(tài)(前驅(qū)并不依賴于這個(gè)點(diǎn)),那么我們考慮一下后繼的情況。
如果這個(gè)點(diǎn)x的唯一的后繼y并沒有被選入,那么說明它原來所有的前驅(qū)都被選入了。我們可以將它選入點(diǎn)集中。但是這樣子可能導(dǎo)致y的唯一后繼z無法被選入了(這種情況就是z被選入點(diǎn)集時(shí)依賴于y),從下圖可以更直觀地看出這種關(guān)系。


圖片1.png

那么這時(shí)候我們就可以有兩種選擇,直接舍棄綠叉邊,又或者將它繼續(xù)往下“推”,那么遞歸地來看這和我們做的第一步是相同的,顯然這么做并不能使得被選入邊集的邊數(shù)增多。
如果這個(gè)點(diǎn)x的唯一的后繼y被選入了,那么情況是類似的,不難證明不會(huì)使得邊數(shù)增多。
綜上所述,通過上面所述的貪心策略能選出最大的點(diǎn)集。

實(shí)現(xiàn):

#include<cstdio>

const int maxn=1000010;  
int a[maxn],team[maxn],head,tail,n;  
int rd[maxn];  
int ans;  
bool bz[maxn];  
  
int main()  
{  
    scanf("%d",&n);  
    for(int i=1;i<=n;i++)  
        scanf("%d",&a[i]),rd[a[i]]++;  
    for(int i=1;i<=n;i++)  
        if(!rd[i])  
            team[++tail]=i;  
    while(head<tail)  
    {  
        int t=team[++head];  
        if(!bz[t]&&!bz[a[t]])  
        {  
            bz[a[t]]=1;  
            ans++;  
            if(!--rd[a[a[t]]])  
            {  
                team[++tail]=a[a[t]];  
            }  
        }  
        bz[t]=1;  
    }  
    for(int i=1;i<=n;i++)  
    {  
        if(!bz[i])  
        {  
            int t=1;  
            bz[i]=1;  
            int c=i;  
            while(a[c]!=i)  
            {  
                c=a[c];  
                bz[c]=1;  
                t++;  
            }  
            ans+=t>>1;  
        }  
    }  
    printf("%d",ans);
}  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容