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
1 2
1 4
2 4
2 3
3 4
Sample Output
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 }