未知:獨立集——題解

題目描述
有一天,一個名叫順旺基的程序員從石頭裏誕生了。又有一天,他學會了冒泡排序和獨立集。在一個圖裏,獨立集就是一個點集,滿足任意兩個點之間沒有邊。於是他就想把這兩個東西結合在一起。衆所周知,獨立集是需要一個圖的。那麼順旺基同學創造了一個算法,從冒泡排序中產生一個無向圖。
這個算法不標準的僞代碼如下:

procedure bubblesortgraph(n, a[]) :
    /*輸入:點數n,1到n的全排列a。
    輸出:一個點數爲n的無向圖G。*/
    創建一個有n個點,0條邊的無向圖G。
    repeat
        swapped = false
        for i 從 1 到 n-1if a[i] > a[i + 1] :
                  在G中連接點a[i]和點a[i + 1]
                  交換a[i]和a[i + 1]
        swapped = true
    until not swapped
    輸出圖G。
//結束。

那麼我們要算出這個無向圖G最大獨立集的大小。但是事情不止於此。順旺基同學有時候心情會不爽,這個時候他就會要求你再回答多一個問題:最大獨立集可能不是唯一的,但有些點是一定要選的,問哪些點一定會在最大獨立集裏。今天恰好他不爽,被他問到的同學就求助於你了。
輸入
兩行。第一行爲N,第二行爲1到N的一個全排列。
輸出
兩行。第一行輸出最大獨立集的大小,第二行從小到大輸出一定在最大獨立集的點的編號(輸入時的序號)。
樣例輸入
3
3 1 2
樣例輸出
2
2 3
數據範圍

30%的數據滿足 N<=16

60%的數據滿足 N<=1,000

100%的數據滿足 N<=100,000 

這題難想是難想,但是……
標程更難理解好不?!
所以做法直接扔標程裏。
所以可能和路由器的代碼風格不一致。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <map>
#include <cstring>
using namespace std;
const int MAXN = 100000;
const int INF = 1e9+7;
int B[MAXN+10], LenB;
int a[MAXN+10], b[MAXN+10];
int A[MAXN+10], LenA;
int L[MAXN+10], R[MAXN+10];
map<pair<int, int>, int> check;
int main(){
    int n;
    scanf("%d", &n);
    for(int i=1;i<=n;i++){
        scanf("%d", &a[i]);
        b[i] = -a[i];//變求下降爲求上升 
    }
    //下面求出最長上升子序列 
    for(int i=1;i<=n;i++){
        int pos = lower_bound(A+1, A+1+LenA, a[i]) - A;//找到a[i]放在A的位置 
        L[i] = pos;
        LenA += int(A[pos] == 0);//計算A的長度 
        A[pos] = a[i];
    }
    for(int i=1;i<=n;i++) B[i] = -INF;
    //下面求出最長下降子序列 
    for(int i=n;i>=1;i--){
        int pos = lower_bound(B+1, B+1+LenB, b[i]) - B;
        R[i] = pos;
        LenB += int(B[pos] == -INF);
        B[pos] = b[i];
    }
    printf("%d\n", LenA);//最長上升子序列長
    for(int i=1;i<=n;i++)
        if(L[i] + R[i] - 1 == LenA)
            check[make_pair(L[i], R[i])]++;//創建二元組 
    LenB=0;
    for(int i=1;i<=n;i++){
        //printf("%d\n",check[make_pair(L[i], R[i])]);
        if(L[i] + R[i] - 1 == LenA && check[make_pair(L[i], R[i])] == 1){
            //有一個奇怪的定理
            //當一個數的向左最長下降長度與向右最長上升長度
            //對於所有數的左最長下降長度與向右最長上升長度中是獨一無二的
            //那麼這個點就符合條件
            //簡單的證明:
            //如果這個點並非唯一
            //那麼這個點就可以被另一個和它相同的點所替代 
            B[++LenB] = i;
        }
    }
    for(int i=1;i<=LenB;i++)
        printf("%d ", B[i]);
    return 0;
}
發佈了59 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章