bzoj1006 [HNOI2008]神奇的国度

Description

K国是一个热衷三角形的国度,连人的交往也只喜欢三角原则.他们认为三角关系:即AB相互认识,BC相互认识,CA相互认识,是简洁高效的.为了巩固三角关系,K国禁止四边关系,五边关系等等的存在.所谓N边关系,是指N个人 A1A2...An之间仅存在N对认识关系:(A1A2)(A2A3)...(AnA1),而没有其它认识关系.比如四边关系指ABCD四个人 AB,BC,CD,DA相互认识,而AC,BD不认识.全民比赛时,为了防止做弊,规定任意一对相互认识的人不得在一队,国王相知道,最少可以分多少支队。

Input

第一行两个整数N,M。1<=N<=10000,1<=M<=1000000.表示有N个人,M对认识关系. 接下来M行每行输入一对朋友

Output

输出一个整数,最少可以分多少队

Sample Input

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

Sample Output

3

HINT

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

 

正解:弦图+最小染色。

详见$CDQ$的《弦图与区间图》,然后也膜了一下xlightgod。。

子图:概念显然。。

诱导子图:对于一个子图里的点,所有的边都在这个图上。

团:完全图。

极大团、最大团:不是其他团子集的团;含有点数最多的团。

最小染色:用最少的颜色给点染色使得相邻点颜色不同。

最大独立集:最大的使任意两个点不相邻的点集。

最小团覆盖:能够覆盖所有点的最小团数。

显然:

最大团大小<=最小染色(团中所有点必须颜色互不相同)

最大独立集<=最小团覆盖(不相邻的两个点不可能在同一个团中)

这道题用到了一些新的概念:

弦:连接环中不相邻两个点的边。

弦图:图中任意一个大于$3$的环都有弦的无向图。也被形象地称为三角图。

单纯点:与它所有相邻的点构成的诱导子图为团的点。

完美消除序列:每次从图中去掉一个单纯点形成的点的序列。

那么一个无向图是弦图当且仅当它有一个完美消除序列。

然后就是求完美消除序列了,这里使用的是最大势$(MCS)$算法。

每个点记录一个势,表示与它相邻的已经在完美消除序列的点的个数。

先把$n$号点弄出来,然后每次把势最大的弄出来,这样依次求出的点的逆序就是完美消除序列,使用链表可以让复杂度降至$O(n)$。

然后这道题说禁止“四边关系”,“五边关系”等,显然是一个弦图,这题是求一个弦图的最小染色。

求最小染色有一个很简单的方法,按照完美消除序列的逆序依次判断点的颜色,与相邻点的颜色不同就行了,这样可以保证求出来的是最小染色。

于是这题我们就成功地解决了。

 

 1 //It is made by wfj_2048~
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <cstdio>
 7 #include <vector>
 8 #include <cmath>
 9 #include <queue>
10 #include <stack>
11 #include <map>
12 #include <set>
13 #define inf (1<<30)
14 #define N (200010)
15 #define il inline
16 #define RG register
17 #define ll long long
18 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
19 
20 using namespace std;
21 
22 vector <int> ep[N];
23 
24 struct edge{ int nt,to; }g[10*N];
25 
26 int head[N],s[N],l[N],p[N],f[N],col[N],n,m,num,ans,best;
27 
28 il int gi(){
29     RG int x=0,q=1; RG char ch=getchar();
30     while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
31     if (ch=='-') q=-1,ch=getchar();
32     while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
33     return q*x;
34 }
35 
36 il void insert(RG int from,RG int to){
37     g[++num]=(edge){head[from],to},head[from]=num; return;
38 }
39 
40 il void work(){
41     n=gi(),m=gi(); for (RG int i=1;i<=n;++i) ep[0].push_back(i);
42     for (RG int i=1,u,v;i<=m;++i) u=gi(),v=gi(),insert(u,v),insert(v,u);
43     for (RG int i=n,now;i;--i){
44     while (1){
45         now=ep[best].back(); if (!l[now]) break;
46         ep[best].pop_back(); while (ep[best].empty()) --best;
47     }
48     l[now]=i,p[i]=now;
49     for (RG int j=head[now],v;j;j=g[j].nt)
50         v=g[j].to,ep[++s[v]].push_back(v),best=max(best,s[v]),f[col[v]]=i;
51     for (RG int j=1;;++j) if (f[j]!=i){ col[now]=j; break; } ans=max(ans,col[now]);
52     }
53     printf("%d\n",ans); return;
54 }
55 
56 int main(){
57     File("country");
58     work();
59     return 0;
60 }
posted @ 2017-06-06 21:11  wfj_2048  阅读(252)  评论(0编辑  收藏  举报