您的位置:首页 > 其它

BZOJ 1006 神奇的国度[弦图 MCS求完美消除序列]

2014-09-17 21:33 369 查看

chordal graph-弦图

1.定义

   弦图(chordalgraph)是指当无向图中任意长度大于3的环都至少有一个弦。所谓弦(chord)是指连接环中不相邻的两个点的边,如下图所示



大家都知道子图的概念,这里加入一个诱导子图(induced subgraph)的定义:



为了更好的理解弦图的概念,我们引进单纯点(simplicialvertex)的定义:N(v)表示与点v相邻的所有点集。一个点称为单纯点当{v}+N(v)的诱导子图为一个团({v}+N(v)的点集以及由这些点集在原图中的所有边的构成的图是一个团)如下图中的红圈圈住的点为单纯点:




 
团:给定无向图G=(V,E)。如果U包含于V,且对任意u∈U,v∈U,存在边(u,v)∈E,则称U是G的完全子图。G的完全子图U是G的团当且仅当U不包含在G的更大的完全子图中。G的最大团是指G中所含顶点数最多的团。下图G中,子集{1,2}是G的大小为2的完全子图。这个完全子图不是最大团,因为它被G的更大的完全子图{1,2,5}包含。{1,2,5}是G的最大团。{1,4,5}和{2,3,5}也是G的最大团:



2.判断方法

   一个无向图是弦图当且仅当它有一个完美消除序列。而完美消除序列(perfect eliminationordering)是指一个点的序列(每个点出现且恰好出现一次)vi在{vi,vi+1,…,vn}的诱导子图中为一个单纯点。于是有了MCS算法,从n到1的顺序依次给点标号(标号为i的点出现在完美消除序列的第i个),设label[i]表示第i个点与多少个已标号的点相邻,每次选择label[i]最大的未标号的点进行标号,伪代码如下:

MCS(G, order)
{
for all vertices v in G do
Label[v] = 0

for i from n to 1 do
{
choose an unnumbered vertex v with largest Label
order[v] = i

for all unnumbered vertices u adjacent to v do
Label[u]++
}
}


然后判断该序列是否是完美消除序列:对于每一个vi,找到{vi+1,vi+2,…,vn}中与vi相邻的标号最小的点vj,

判断其它{vi+1,vi+2,…,vn}中与vi相邻的点是否与vj相邻,若不相邻则不是完美消除序列。从而可以判断是不是弦图。

 

3.扩展

   弦图的方法有着很多经典用途:例如用最少的颜色给每个点染色使得相邻的点染的颜色不同,通过完美消除序列从后往前依次给每个点染色,给每个点染上可以染的最小的颜色;最大独立集问题,选择最多的点使得任意两个点不相邻,通过完美消除序列从前往后能选就选。

   我们再引入区间图的思想,

会惊奇地发现它也是弦图。给定一些区间,定义一个相交图为每个顶点表示一个区间,两个点有边当且仅当两个区间的交集非空,如下图所示的区间图:




很显然区间图一定是弦图。这是因为如果存在一个长度大于3的无弦环,刚Ii与Ii+1相交的部分pi一定严格递增或严格递减,以递增为例,即p1< pn。但由于第一个I1与最后一个In相交刚得出pn <p1产生矛盾。所以区间图一定是弦图。给定n个区间,要求选择最多的区间使得区间不互相重叠,这个问题就是区间图的最大独立集问题。

/*************************************************************************
> File Name: 67.cpp
> Author: wjzdmr
> Mail: wjzdmr@gmail.com
> Created Time: 2014年09月17日 星期三 20时03分40秒
************************************************************************/

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <list>
#include <deque>
#include <queue>
#include <cctype>
#include <map>
#include <set>
#include <bitset>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <cassert>
#include <limits>
#include <fstream>

using namespace std;

#define mem(A, X) memset(A, X, sizeof A)
#define pb(x) push_back(x)
#define mp(x,y) make_pair((x),(y))
#define vi vector<int>
#define all(x) x.begin(), x.end()
#define foreach(e,x) for(__typeof(x.begin()) e=x.begin();e!=x.end();++e)
#define sz(x) (int)((x).size())
#define sl(a) strlen(a)
#define rep(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i))
#define Rep(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
#define min3(a,b,c) min(a,min(b,c))
#define max3(a,b,c) max(a,max(b,c))
#define dbg(a) cout << a << endl;
#define fi first
#define se second
typedef long long int64;
int gcd(const int64 &a, const int64 &b) { return b == 0 ? a : gcd(b, a % b); }
int64 int64pow(int64 a, int64 b){ if (b == 0) return 1; int64 t = int64pow(a, b / 2); if (b % 2) return t * t * a; return t * t; }
const int inf = 1 << 30;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int MAX_N = 10005;

int n, m;
vi arr[MAX_N];
int R[MAX_N], SA[MAX_N], label[MAX_N];

priority_queue <pair<int, int> > heap;

void work()
{
Rep(i, 1, n) {
arr[i].clear();
}

int u, v;
Rep(i, 1, m) {
scanf("%d%d", &u, &v);
arr[u].pb(v);
arr[v].pb(u);
}

fill(R + 1, R + n + 1, -1);
fill(label + 1, label + n + 1, 0);

Rep(i, 1, n) {
heap.push(mp(0, i));
}

//MCS求弦图的完美消除序列
for (int cnt = n; cnt >= 1; ) {
int id = heap.top().se;
heap.pop();

if (R[id] != -1)
continue;
SA[cnt] = id;
R[id] = cnt--;

rep(i, 0, sz(arr[id])) {
int u = arr[id][i];

if (R[u] != -1)
continue;

label[u]++;

heap.push(mp(label[u], u));
}
}
}

void Color(int u)
{
rep(i, 0, sz(arr[u])) {
int v = arr[u][i];
if (label[v] == -1)
continue;
R[label[v]] = u;
}

for (int i = 1; label[u] == -1; ++i) {
if (R[i] != u)
label[u] = i;
}
}

int Color_Graph()
{
fill(label + 1, label + n + 1, -1);
fill(R + 1, R + n + 1, -1);

for (int i = n; i > 0; --i)
Color(SA[i]);
int ans = 0;
Rep(i, 1, n)
ans = max(ans, label[i]);
return ans;
}
int main()
{
while (cin >> n >> m) {
work();
cout << Color_Graph() << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: