弦图问题初步
弦图是什么:一个无向图称为弦图当图中任意长度大于3的环都至少有一个弦(不存在中间无边的长度大于三的环)
弦图的每一个诱导子图一定是弦图。
弦图的判定:用MCS求完美消除子序列,再判断求出来的是否是完美消除序列。
定理:一个无向图是弦图当且仅当它有一个完美消除序列。
单纯点(simplicial vertex):设N(v)表示与点v相邻的点集。一个点称为单纯点当{v} + N(v)的诱导子图为一个团。
完美消除序列(perfect elimination ordering)
定义:一个点的序列(每个点出现且恰好出现一次)v1, v2, …, vn满足vi在{vi, vi+1,…,vn}的诱导子图中为一个单纯点。
MCS:从1--n给点标号。先任意选一个点作为完美消除序列的末尾,在将它相邻的点势能+1;在选取势能最大的点,并重复+1的步骤,直至标号到1。用链表实现这个过程
完美消除序列判定:从后往前扫,利用已经判断过的点是单纯点(即可以构成团)设{vi+1,…,vn}中所有与vi相邻的点依次为vj1, …, vjk。只需判断vj1是否与vj2, …, vjk相邻即可(注意:vj1是已经判定过的点中标号最小的点)。
弦图染色:用最少的颜色给每个点染色使得相邻的点染的颜色不同。
完美消除序列从后往前依次给每个点染色,给每个点染上可以染的最小的颜色。
弦图最大独立集:选择最多的点使得任意两个点不相邻。
完美消除序列从前往后能选就选。
弦图最小团覆盖:用最少个数的团覆盖所有的点。
最大独立集数 = 最小团覆盖数
弦图应用
区间图(Interval Graph)
定义: 给定一些区间,定义一个相交图为每个顶点表示一个区间,两个点有边当且仅当两个区间的交集非空。
一个图为区间图当它是若干个区间的相交图。
区间图一定是弦图。
经典问题:
1. 给定n个区间,要求选择最多的区间使得区间不互相重叠: 建区间图,相当于求最大独立集
2. 有n个积木,高度均为1,第i个积木的宽度范围为[Li, Ri],选择一个积木的下落顺序使得最后积木总高度尽可能小: 弦图最小染色、同一种颜色表示可以出现在同一层
例题1:
bzoj 1006 神奇的国度
弦图染色裸题
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 #define maxn 1002000 7 #define maxm 10020 8 9 struct node{ 10 int next,to; 11 }e[maxn * 2]; 12 struct node2{ 13 int id,next; 14 }link_[maxn * 2]; 15 int hd[maxn]; 16 int head[maxn],cnt; 17 int n,m; 18 int col[maxn],tot,vis[maxn],lb[maxn]; 19 int a[maxn]; 20 21 inline void adde(int x,int y){ 22 e[++cnt].to = y; 23 e[cnt].next = head[x]; 24 head[x] = cnt; 25 } 26 inline void insert(int x,int y){ 27 int a = hd[x]; 28 hd[x] = ++tot; 29 link_[tot].id = y , link_[tot].next = a; 30 } 31 inline void del(int x){ 32 hd[x] = link_[hd[x]].next; 33 } 34 inline int find(int x){ 35 while ( hd[x] ){ 36 if ( !vis[link_[hd[x]].id] ) return link_[hd[x]].id; 37 hd[x] = link_[hd[x]].next; 38 } 39 return 0; 40 } 41 void MCS(){ 42 for (int i = 1 ; i <= n ; i++){ 43 insert(0,i); 44 } 45 a[n] = 1 , vis[1] = 1; 46 for (int i = head[1] ; i ; i = e[i].next){ 47 insert(++lb[e[i].to],e[i].to); 48 } 49 int p = 1; 50 for (int i = n - 1 ; i >= 1 ; i--){ 51 int cur = 0; 52 while ( !cur && p >= 0 ) cur = find(p) , p--; 53 p++; 54 vis[cur] = 1 , a[i] = cur; 55 for (int i = head[cur] ; i ; i = e[i].next){ 56 insert(++lb[e[i].to],e[i].to); 57 p = max(p,lb[e[i].to]); 58 } 59 } 60 } 61 void solve(){ 62 for (int i = 1 ; i <= n ; i++) vis[i] = 0; 63 tot = 0; 64 for (int i = n ; i >= 1 ; i--){ 65 int j = 0; 66 for (j = head[a[i]] ; j ; j = e[j].next){ 67 vis[col[e[j].to]] = 1; 68 } 69 j = 1; 70 while ( vis[j] ) j++; 71 col[a[i]] = j; 72 for (j = head[a[i]] ; j ; j = e[j].next){ 73 vis[col[e[j].to]] = 0; 74 } 75 } 76 for (int i = 1 ; i <= n ; i++) tot = max(tot,col[i]); 77 printf("%d\n",tot); 78 } 79 int main(){ 80 //freopen("input.txt","r",stdin); 81 scanf("%d %d",&n,&m); 82 for (int i = 1 ; i <= m ; i++){ 83 int x,y; 84 scanf("%d %d",&x,&y); 85 adde(x,y); 86 adde(y,x); 87 } 88 MCS(); 89 solve(); 90 return 0; 91 }
例题2:
bzoj 124 Zju1015 Fishing Net弦图判定
弦图判定裸题
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 #define maxn 1002000 7 #define maxm 10020 8 9 struct node{ 10 int next,to; 11 }e[maxn * 2]; 12 struct node2{ 13 int id,next; 14 }link_[maxn * 2]; 15 int hd[maxn]; 16 int head[maxn],cnt; 17 int n,m; 18 int c[maxn],tot,vis[maxn],lb[maxn],use[maxn]; 19 int a[maxn],dfstime; 20 21 inline void adde(int x,int y){ 22 e[++cnt].to = y; 23 e[cnt].next = head[x]; 24 head[x] = cnt; 25 } 26 inline void insert(int x,int y){ 27 int a = hd[x]; 28 hd[x] = ++tot; 29 link_[tot].id = y , link_[tot].next = a; 30 } 31 inline void del(int x){ 32 hd[x] = link_[hd[x]].next; 33 } 34 inline int find(int x){ 35 while ( hd[x] ){ 36 if ( !vis[link_[hd[x]].id] ) return link_[hd[x]].id; 37 hd[x] = link_[hd[x]].next; 38 } 39 return 0; 40 } 41 void MCS(){ 42 for (int i = 1 ; i <= n ; i++){ 43 insert(0,i); 44 } 45 a[n] = 1 , vis[1] = 1; 46 for (int i = head[1] ; i ; i = e[i].next){ 47 insert(++lb[e[i].to],e[i].to); 48 } 49 int p = 1; 50 for (int i = n - 1 ; i >= 1 ; i--){ 51 int cur = 0; 52 while ( !cur && p >= 0 ) cur = find(p) , p--; 53 p++; 54 vis[cur] = 1 , a[i] = cur; 55 for (int i = head[cur] ; i ; i = e[i].next){ 56 insert(++lb[e[i].to],e[i].to); 57 p = max(p,lb[e[i].to]); 58 } 59 } 60 } 61 bool check(){ 62 for (int i = 1 ; i <= n ; i++) vis[i] = 0; 63 use[a[n]] = 1; 64 for (int i = n - 1 ; i >= 1 ; i--){ 65 dfstime++, cnt = 0; 66 for (int j = head[a[i]] ; j ; j = e[j].next){ 67 if ( use[e[j].to] ) c[++cnt] = e[j].to; 68 } 69 for (int j = head[c[1]] ; j ; j = e[j].next){ 70 vis[e[j].to] = dfstime; 71 } 72 for (int j = 2 ; j <= cnt ; j++) if ( vis[c[j]] != dfstime ) return 0; 73 use[a[i]] = 1; 74 } 75 return 1; 76 } 77 int main(){ 78 //freopen("input.txt","r",stdin); 79 scanf("%d %d",&n,&m); 80 for (int i = 1 ; i <= m ; i++){ 81 int x,y; 82 scanf("%d %d",&x,&y); 83 adde(x,y); 84 adde(y,x); 85 } 86 MCS(); 87 if ( check() ) printf("Perfect\n"); 88 else printf("Imperfect\n"); 89 return 0; 90 }
就先写这么多吧,以后遇到好题再加(现在只有裸题,好惨)