zoukankan      html  css  js  c++  java
  • 图着色问题

    一、图着色问题

    (1)图的m可着色判定问题

    给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。是否有一种着色法使G中每条边的2个顶点着不同颜色。

    (2)图的m可着色优化问题

    若一个图最少需要m种颜色才能使图中每条边连接的2个顶点着不同颜色,则称这个数m为该图的色数。


    二、m可着色判定问题的解法

    【算法】

    (1)通过回溯的方法,不断的为每一个节点着色,在前面cur-1个节点都合法的着色之后,开始对第cur-1个节点进行着色,

    (2)这时候枚举可用的m个颜色,通过和第cur-1个节点相邻的节点的颜色,来判断这个颜色是否合法

    (3)如果找到那么一种颜色使得第cur-1个节点能够着色,那么说明m种颜色的方案在当前是可行的。
    (4)cur每次迭代加1,如果cur增加到N并通过了检测,说明m种颜色是可满足的。

    (5)注意,这里只是要求判断m种颜色是否可满足,所以找到任何一种方案就可以了。

    【代码实现】

    #include<iostream>
    #include<cstring>
    using namespace std;
    const int maxn = 105;
    int G[maxn][maxn];
    int color[maxn];
    bool ans;
    int n,m,k;
    void init(){
        ans = 0;
        memset(G, 0 , sizeof G);
        memset(color, 0 , sizeof color);
    }
    
    void dfs(int cur){
        if(cur > n) {
            ans = 1;
            return;    
        } 
        for(int i=1; i<=m; i++){ //对cur结点尝试使用每一种颜色进行涂色 
        
            bool flag = 1;
            //cur之前的结点必被涂色
            for(int j=1; j<cur; j++){
                if(G[j][cur] == 1 && color[j] == i){
                    flag = 0;//只要有一个冲突都不行 
                    break;
                }
            } 
            //如果可以涂上i颜色,则考虑下一个结点的情况 
            if(flag){
                color[cur] = i;
                dfs(cur + 1);
                
            } 
            //如果到这一步第cur个结点无法着色,则返回探寻其他方案 
            else color[cur] = 0;//回溯 ;
        }
        
    }
    
    
    int main(){
        while(cin>>n>>k>>m){
            init(); 
            for(int i=1; i<=k; i++){
                int x,y;
                cin>>x>>y;
                G[x][y] = G[y][x] = 1;
            }
            dfs(1);
            cout<<ans<<endl;
        }
        return 0;
    }

    三、m可着色拓展

    【问题】在上述基础上,求出m种颜色能够给图G涂色的总总方案数量

    【算法】由于这个时候要求总方案数量,所以在找到一种可行方案后,总是进行回溯再搜索其他的解决方案,与上面不同,上面是只需要找出一种方案即可,所以如果找到了就不需要再回溯了,所以在这里只需要把回溯语句的位置写到dfs语句的后面即可。

    【代码实现】

    #include<iostream>
    #include<cstring>
    using namespace std;
    const int maxn = 105;
    int G[maxn][maxn];
    int color[maxn];
    int ans;
    int n,m,k;
    void init(){
        ans = 0;
        memset(G, 0 , sizeof G);
        memset(color, 0 , sizeof color);
    }
    
    void dfs(int cur){
        if(cur > n) {
            ans++;
            return;    
        } 
        for(int i=1; i<=m; i++){ //对cur结点尝试使用每一种颜色进行涂色 
        
            bool flag = 1;
            //cur之前的结点必被涂色
            for(int j=1; j<cur; j++){
                if(G[j][cur] == 1 && color[j] == i){
                    flag = 0;//只要有一个冲突都不行 
                    break;
                }
            } 
            //如果可以涂上i颜色,则考虑下一个结点的情况 
            if(flag){
                color[cur] = i;
                dfs(cur + 1);
                color[cur] = 0;//回溯 
            } 
        }
        
    }
    
    
    int main(){
        while(cin>>n>>k>>m){
            init(); 
            for(int i=1; i<=k; i++){
                int x,y;
                cin>>x>>y;
                G[x][y] = G[y][x] = 1;
            }
            dfs(1);
            cout<<ans<<endl;
        }
        return 0;
    }

    四、图的m可着色优化问题

    【问题】给定无向图图G,顶点数N,边集E, 要求用最少的颜色使得图中每一个顶点都涂上颜色,要求有边直接相连的顶点不能涂同样的颜色,问最少需要多少种颜色?

    【算法】

    (1)一种朴素的想法就是在上述图着色的结论基础上,使用二分法求出所需要的最小颜色数,范围1~N。但是存在大量的重复计算,复杂度过高。

    (2)可以在之前的DFS上加上一维颜色数,一边增加顶点数一边增加颜色数,留下能够使得1~N顶点都满足的最少的颜色数

    【题目链接】分考场

    题目大意是:有n个学生分考场,其中有k对学生认识,认识的学生不能在同一个考场,问最少需要多少个考场。

    相当于有n个顶点,k条边,有边相连的顶点不能涂相同的颜色,问最少需要多少颜色。

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn = 105;
    const int inf = 0x3f3f3f3f;
    int n,k;
    int x,y;
    int room[maxn];//room[i]表示i号房间的当前人数
    int stu[maxn][maxn];//stu[i][j]表示第i个房间的第 j个学生是谁
    int G[maxn][maxn];//存图
    int ans ; 
    void init(){
        memset(room ,  0, sizeof room);
        memset(stu, 0,  sizeof stu);
        memset(G,  0, sizeof G);
        ans = inf;
    }
    
    //表示给第cur个学生安排房间 
    void dfs(int cur , int tot){
        if(tot >= ans) return ;
        //如果学生都安排好了,则记录这种方法所导出的ans 
        if(cur > n){
            ans = min(ans , tot);
            return ;
        } 
        //如果还没安排好,则给cur找合适的房间 
        for(int i=1; i<=tot; i++){
            //看第i号房间里的所有人是否与其冲突
            int len = room[i];
            bool flag = 1;
            for(int j=1; j<=len; j++){
                if(G[stu[i][j]][cur]){
                    flag = 0;
                    break;
                }
            }
            //如果找到房间了 就去安排下一个学生 
            if(flag){
                room[i]++;//这个房间里多住了cur
                stu[i][room[i]] = cur;
                //继续深搜 
                dfs(cur+1, tot); 
                //回溯
                stu[i][room[i]] = 0;
                room[i]--;
                
            } 
        }
        //如果这 tot个房间都不行,则需要新开间房给这个学生
        room[tot+1]++;
        stu[tot+1][room[tot+1]] = cur;
        //继续深搜 
        dfs(cur + 1 , tot + 1); 
        //回溯 
        stu[tot+1][room[tot+1]] = 0;
        room[tot+1]--;
    }  
    
    
    int main(){
        while(cin>>n>>k){
            init();
            for(int i=1; i<=k; i++){
                cin>>x>>y;
                G[x][y] = G[y][x] = 1;
            }
            dfs(1,0);
            cout<<ans<<endl;
        }
    }
  • 相关阅读:
    C#路径中获取文件全路径、目录、扩展名、文件名称
    c#FTP应用---windows iis
    c#FTP应用---FileZilla Server
    在VS2010中使用Git管理源代码
    ABB机器人---PCSDK简介
    几款软件需求分析工具
    快速排序
    springmvc和struts2的区别比较
    Struts中ActionContext和ServletActionContext的比较
    设计模式--适配器模式
  • 原文地址:https://www.cnblogs.com/czsharecode/p/10558732.html
Copyright © 2011-2022 走看看