1. 程式人生 > >bzoj 1098 [POI2007] 辦公樓 biu

bzoj 1098 [POI2007] 辦公樓 biu

include stream esp 如何 img 復雜度 ans 圖片 之間

# 解題思路

畫畫圖可以發現,只要是兩個點之間沒有相互連邊,那麽就必須將這兩個人安排到同一個辦公樓內,如圖所示:

技術分享圖片

那,我們可以建立補圖,就是先建一張完全圖,然後把題目中給出的邊都刪掉,這就是一張補圖,顯然補圖中相互連邊的點就放在同一棟辦公樓內。

我們可以用並查集來完成,但是數據範圍顯然不允許用這樣的方法,建圖的復雜度是 $N^2$ 的。所以考慮另一種方法:

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

之後對每一個點都進行這樣的操作,那麽之後要刪除的點都要滿足既沒有被刪除也沒有被標記。這樣做下來的復雜度還是 $N^2$ 的。再來想想如何優化,我們如果在刪點的時候,不去枚舉那些已經被刪除的點。那所有的刪點的操作總時間復雜度是 $M$ 的,因為每個邊都要只遍歷一次。如何優化?鏈表啊。。。

# 附上代碼

#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; }

bzoj 1098 [POI2007] 辦公樓 biu