1. 程式人生 > >HNOI2008]神奇的國度

HNOI2008]神奇的國度

進行 更新 題解 鞏固 玩意兒 lock space ans 相交

題目描述

K國是一個熱衷三角形的國度,連人的交往也只喜歡三角原則.他們認為三角關系:即AB相互認識,BC相互認識,CA相互認識,是簡潔高效的.為了鞏固三角關系,K國禁止四邊關系,五邊關系等等的存在.

所謂N邊關系,是指N個人 A1A2...An之間僅存在N對認識關系:(A1A2)(A2A3)...(AnA1),而沒有其它認識關系.比如四邊關系指ABCD四個人 AB,BC,CD,DA相互認識,而AC,BD不認識.全民比賽時,為了防止做弊,規定任意一對相互認識的人不得在一隊,國王相知道,最少可以分多少支隊。

輸入輸出格式

輸入格式:

第一行兩個整數N,M。1<=N<=10000,1<=M<=1000000.表示有N個人,M對認識關系. 接下來M行每行輸入一對朋友

輸出格式:

輸出一個整數,最少可以分多少隊

輸入輸出樣例

輸入樣例#1: 復制

4 5
1 2
1 4
2 4
2 3
3 4

輸出樣例#1: 復制

3

說明

一種方案(1,3)(2)(4)


題解

弦圖染色我為什麽要學這種沒用的東西==

弦圖

就是一個圖中所有長度大於3的環都有至少一條弦

然後說一下弦圖的概念

單純點:一個點和與ta相鄰的點集所構成的誘導子圖是一個團

所以一個弦圖至少有一個單純點

完美消除序列:就是一個點的序列\(V_i\)在原圖上每一個點\(V_i\),在\(V_{i~n}\)所構成的圖中都是一個單純點

如果一個圖是弦圖,那麽ta一定有且只有一個完美消除序列

求完美消除序列?

就是維護每個點與多少個被染色的點相鄰\(d[i]\)

然後每次都選擇\(d[i]\)最大的中放進去最晚的,並對ta進行染色

再更新與ta相鄰的點

最後把這個選出的點放進序列中並以後不再選ta

這樣就得到了一個倒序的完美消除序列

然後弦圖的極大團就是每個節點最大的勢\(d[]+1\)

弦圖的最大獨立集

完美消除序列從前往後能選就選

弦圖的最小團覆蓋=最大獨立集

區間圖

就是有一些線段,這些線段相互平行

然後我們要把邊當做點,能相交的線段連邊,就構成了區間圖

區間圖也是弦圖

然後這玩意兒也可以做區間覆蓋的問題但是我不會

大概就是把區間按照左/右區間排序然後染色或者按照完美消除序列加邊就好了

然後這個題就是求個最大團就沒了

代碼

#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
const int M = 10005 ;
using namespace std ;
inline int read() {
    char c = getchar() ; int x = 0 , w = 1 ;
    while(c>'9' || c <'0') { if(c=='-') w = -1 ; c = getchar() ; }
    while(c>='0' && c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    return x*w ;
}

bool vis[M] ;
vector < int > vec[M] ;
int n , m , num , hea[M] , best ;
int cnt , q[M] , d[M] , Ans ;
struct E { int nxt , to ; } edge[M * 200] ;
inline void add_edge(int from , int to) {
    edge[++num].nxt = hea[from] ; 
    edge[num].to = to ;
    hea[from] = num ;
}


int main() {
    n = read() ; m = read() ; cnt = n + 1 ;
    for(int i = 1 , u , v ; i <= m ; i ++) {
        u = read() ; v = read() ;
        add_edge(u , v) ; add_edge(v , u) ;
    }
    for(int i = 1 ; i <= n ; i ++) vec[0].push_back(i) ; 
    for(int i = 1 ; i <= n ; i ++) {
        int k = 0 ; bool ftg = true ;
        while(ftg) {
            for(int j = vec[best].size() - 1 ; j >= 0 ; j --) {
                if(vis[vec[best][j]]) vec[best].pop_back() ;
                else { k = vec[best][j] ; ftg = false ; break ; }
            }
            if(ftg) -- best ;
        }
        q[--cnt] = k ; vis[k] = true ;
        for(int i = hea[k] ; i ; i = edge[i].nxt) {
            int v = edge[i].to ; if(vis[v]) continue ;
            vec[++d[v]].push_back(v) ; best = max(best , d[v]) ;
        }
    }
    for(int i = n ; i >= 1 ; i --) Ans = max(Ans , d[i] + 1) ;
    cout << Ans << endl ;
    return 0 ;
}

HNOI2008]神奇的國度