HNOI2008]神奇的国度

题目描述

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 ;
}
posted @ 2019-01-21 11:19  beretty  阅读(112)  评论(0编辑  收藏  举报