题目描述
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 ;
}