顶点着色问题应用


1. n个学生对m个宣讲会中的若干个感兴趣,如何安排宣讲会的时间(每个宣讲会持续的时间相同),使得每个学生对自己感兴趣的宣讲会时间不冲突,且宣讲会的总时间最短?


此问题可以转化成顶点着色问题。

把每个宣讲会看作是一些散布的点,对于每个学生,把他感兴趣的宣讲会之间两两相连,如:

学生A希望参加宣讲会1、2、3

学生B希望参加宣讲会1、3、4          则:

 

设宣讲会1、2、3、4的着色分别为c1、c2、c3、c2,4与2着同样的颜色,则可以这样安排宣讲会的时间,假设持续时间为一小时,宣讲会1在1点开,2在2点开,3在3点开,4与2时间一样在2点开。


2. 对N个区间进行着色,有重叠的区间不能着同样的颜色。

可转化为顶点着色问题,但顶点着色问题是NP的,至今没有一个已知的好算法,所以对图的色数进行估计以及在寻找使用的颜色数“不太大”的情形下顶点着色的某些方法又有非常重要的意义。于是顶点着色的贪婪算法应运而生。

顶点着色的贪婪算法是按顺序取第一个可用的颜色而忽略对以后的顶点可能会产生的后果。使用正整数对顶点着色,因此可以谈论一种颜色小于另一种颜色了。


(1) 色数

设G =(V,E)是一个图,G的顶点着色就是G的每个顶点指定一种颜色,且使得相邻顶点有不同的颜色。如果这些颜色选自于一个 k 种颜色的集合而不管 k 种颜色是否都用到,那么顶点着色称为 k-顶点着色,简称为k-着色。G有一个 k 着色,那么G是 k-可着色的。使得G是 k-可着色的最小的 k 称为G的色数χ(G)表示。

(2) 顶点着色的贪婪算法

设G是一个图,它的顶点按某一顺序记为x1,x2,...,xn。

i ) 对顶点x1指定颜色1.

ii) 对每个 i = 2,3,...,n,另 p 是与 xi 邻接的顶点 x1,x2,...,xi-1 中没有任何一个顶点着色 p 的最小的颜色,并且对 xi 指定颜色 p。


下面是一个定理:

设G是一个图,对于该图顶点的最大度Δ,那么贪婪算法产生G的顶点的一-着色(但并不意味着Δ + 1种颜色都用到),

 

(3) 算法设计

回到原始问题:对N个区间进行着色,有重叠的区间不能着同样的颜色。下面是解决这个问题的算法,摘自<编程之美>。

共N个区间,对这N个区间按照区间开始从小到大排序,设为:

[b[i], e[i]] 0 <= i < N

color[i]为颜色号 0 <= i < N

color[i] = 0 i = 0时,

color[i+1] = color[i] 第 i 区间与第 i + 1 区间无重叠时,

color[i + 1] = color[i] + 1 第 i 区间与第 i + 1 区间有重叠时。


算法如下:

int overlap(int b1, int e1, int b2, int e2) {   //判断两区间是否有重叠的函数
    if (b2 >= e1 || b1 >= e2)
        return 0;      //没有重叠
    else
        return 1;      //有重叠
}

int intervalColoring(int b[], int e[], int color[], int N)
{
    int nMaxColors = 0, i, k, j;
    int isForbidden[N];//false:0;true:1
    memset(isForbidden, 0, sizeof isForbidden);

    for (i = 0; i < N;i++) {
        for (k = 0;k < nMaxColors;k++)  /** a */
            isForbidden[k] = 0;
        for (j = 0;j < i;j++)           /** b */
            if (overlap(b[j], e[j], b[i], e[i]))
                isForbidden[color[j]] = 1;
        for (k = 0;k < nMaxColors;k++)  /** c */
            if (isForbidden[color[k]] == 0)
                break;
        if (k < nMaxColors)
            color[i] = k;
        else {
            color[i] = nMaxColors;
            ++nMaxColors;
        }
    }// for
    return nMaxColors;
}

分析:

(a) 把这当前已着色的nMaxColors种颜色设为可用。

(b) j从区间0开始到区间 i-1与当前待着色区间 i 判断两区间是否有重叠,若有则着区间 j 的颜色不能用来着区间 i 。

(c) k从0到nMaxColors - 1,判断这nMaxColors种颜色有能着区间 i 的。


测试代码如下:

#include 
#include 

int overlap(int b1, int e1, int b2, int e2);
int intervalColoring(int b[], int e[], int color[], int N);
int main(void)
{
    int i, N = 4;
    int b[] = {1, 2, 3, 3}, e[] = {5, 3, 4, 6};
    int color[N], nMaxColors = 0;

    nMaxColors = intervalColoring(b, e, color, N);

    printf("nMaxColors = %d\n", nMaxColors);
    printf("\ncolor of the intervals:\n");
    for (i = 0;i < N;i++)
        printf("interval %d: color %d\n",i, color[i]);

    return 0;
}

输出:



你可能感兴趣的:(算法之美,程序设计)