弦图问题初步

弦图是什么:一个无向图称为弦图当图中任意长度大于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 }

就先写这么多吧,以后遇到好题再加(现在只有裸题,好惨)

 
posted @ 2016-05-06 17:38  zhangqingqi  阅读(459)  评论(0编辑  收藏  举报