bzoj 1098 [POI2007] 辦公樓 biu

# 解題思路

畫畫圖能夠發現,只要是兩個點之間沒有相互連邊,那麼就必須將這兩我的安排到同一個辦公樓內,如圖所示:ios

那,咱們能夠創建補圖,就是先建一張徹底圖,而後把題目中給出的邊都刪掉,這就是一張補圖,顯然補圖中相互連邊的點就放在同一棟辦公樓內。優化

咱們能夠用並查集來完成,可是數據範圍顯然不容許用這樣的方法,建圖的複雜度是 $N^2$ 的。因此考慮另外一種方法:spa

將原圖創建好,在原圖中,從一個點開始,把這個點所可以直接到達的點標記出來,這些點是不能夠放在一塊兒的。而後將這些點刪除。code

以後對每個點都進行這樣的操做,那麼以後要刪除的點都要知足既沒有被刪除也沒有被標記。這樣作下來的複雜度仍是 $N^2$ 的。再來想一想如何優化,咱們若是在刪點的時候,不去枚舉那些已經被刪除的點。那全部的刪點的操做總時間複雜度是 $M$ 的,由於每一個邊都要只遍歷一次。如何優化?鏈表啊。。。blog

 

# 附上代碼

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
template <typename T> inline void read(T &x) {
    x = 0; T f = 1; char c = getchar();
    while (c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while (c <= '9' && c >= '0') {x = x*10 + c-'0'; c = getchar();}
    x *= f;
}
const int maxn = 4e6+3;
int n, m, head[maxn], cnt, ans, pre[maxn], sur[maxn], num[maxn];
bool vis[maxn], del[maxn];
struct edge {int nxt, to;}ed[maxn];
inline void addedge(int x, int y) {
    ed[++cnt].nxt = head[x], head[x] = cnt, ed[cnt].to = y;
}
inline void DEL(int x) {
    sur[pre[x]] = sur[x];
    pre[sur[x]] = pre[x];
    del[x] = 1;
}
inline void BFS(int u) {
    queue<int> Q;
    Q.push(u), vis[u] = 1;
    while (!Q.empty()) {
        int now = Q.front();
        Q.pop();
        num[ans] ++;
        for(int i=head[now]; i; i=ed[i].nxt)
            vis[ed[i].to] = 1;
        for(int i=sur[0]; i<=n; i=sur[i])
            if(!vis[i] && !del[i]) Q.push(i), DEL(i);
        for(int i=head[now]; i; i=ed[i].nxt)
            vis[ed[i].to] = 0;
    }
}
int main() {
    read(n), read(m);
    int u, v;
    for(int i=1; i<=m; i++) {
        read(u), read(v);
        addedge(u, v), addedge(v, u);
    }
    for(int i=0; i<=n; i++)
        pre[i] = i-1, sur[i] = i+1;
    for(int i=1; i<=n; i++)
        if(!del[i]) del[i] = 1, ans ++, BFS(i), DEL(i);
    sort(num+1, num+1+ans);
    printf("%d\n", ans);
    for(int i=1; i<=ans; i++) printf("%d ", num[i]);
    return 0;
}
相關文章
相關標籤/搜索