zoukankan      html  css  js  c++  java
  • PKU 1129 Channel Allocation(染色问题||搜索+剪枝)

    题目大意建模:

    一个有N个节点的无向图,要求对每个节点进行染色,使得相邻两个节点颜色都不同,问最少需要多少种颜色?

    那么题目就变成了一个经典的图的染色问题

    例如:N=7

    A:BCDEFG

    B:ACDEFG

    C:ABD

    D:ABCE

    E:ABDF

    F:ABEG

    G:ABF

    画成图就是:

    首先考虑四色定理:任何一张地图只用四种颜色就能使具有共同边界的国家着上不同的颜色

    judge(int x,int y)枚举判断x的邻接点中是否着色y颜色的

    1.正向考虑dfs(int num,int color)从第一个点开始从前往后用color种颜色给num个点着色

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    char ch[30];
    bool vis[30];
    int n,col[30],graph[30][30];
    bool judge(int x,int y)
    {//判断在x点是否可以着色y 
        for(int i=0;i<n;i++){
            if(graph[x][i])
                if(col[i]==y) return false;
        }
        return true;
    }
    bool dfs(int num,int color)
    {
        if(num>n)
            return true;
        for(int i=0;i<num;i++){//dfs()函数含义体现在此处for循环
            if(!vis[i]){ 
                vis[i]=true;
                for(int j=1;j<=color;j++){
                    if(judge(i,j)){
                        col[i]=j;//着色 
                        if(dfs(num+1,color))
                            return true;
                    }
                }
                vis[i]=false;
            }
        }
        return false;
    }
    int main()
    {
        while(scanf("%d",&n),n){
            memset(graph,0,sizeof(graph));
            for(int i=0;i<n;i++){
                cin>>ch;for(int j=2;j<strlen(ch);j++)
                    graph[ch[0]-'A'][ch[j]-'A']=1;
            }
            for(int i=1;i<=4;i++){
                memset(vis,0,sizeof(vis));
                if(dfs(1,i)){
                    if(i==1)
                        printf("1 channel needed.
    ");
                    else 
                        printf("%d channels needed.
    ",i);
                    break;
                }
            }
        }
    }

    2.反向考虑dfs(int num,int color)从第n个点开始从后往前用color种颜色给剩下的num个点着色,同时减少vis[30]数组的开辟

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    char ch[30];
    int n,col[30],graph[30][30];
    bool judge(int x,int y)
    {
        for(int i=0;i<n;i++){
            if(graph[x][i])
                if(col[i]==y) return false;
        }
        return true;
    }
    bool dfs(int num,int color)
    {
        if(!num)
            return true;//dfs()函数含义体现在此处for循环
        for(int i=num-1;i>=0;i--){//或者for(int i=0;i<num;i++)
            if(!col[i]){
                for(int j=1;j<=color;j++){
                    if(judge(i,j)){
                        col[i]=j; 
                        if(dfs(num-1,color))
                            return true;
                    }
                }
                col[i]=0;
            }
        }
        return false;
    }
    int main()
    {
        while(scanf("%d",&n),n){
            memset(graph,0,sizeof(graph));
            for(int i=0;i<n;i++){
                cin>>ch;for(int j=2;j<strlen(ch);j++)
                    graph[ch[0]-'A'][ch[j]-'A']=1;
            }
            for(int i=1;i<=4;i++){
                memset(col,0,sizeof(col));
                if(dfs(n,i)){
                    if(i==1)
                        printf("1 channel needed.
    ");
                    else 
                        printf("%d channels needed.
    ",i);
                    break;
                }
            }
        }
    }

    3.dfs(int num,int color)从第num个点开始用color种颜色着色,函数含义体现在自身

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    char ch[30];
    bool vis[30];
    int n,col[30],graph[30][30];
    bool judge(int x,int y)
    {
        for(int i=0;i<n;i++){
            if(graph[x][i])
                if(col[i]==y) return false;
        }
        return true;
    }
    bool dfs(int num,int color)
    {
        if(num>n)
            return true;
        for(int i=num-1;i<n;i++){//和第一种正向考虑的区别 
            if(!vis[i]){
                vis[i]=1;
                for(int j=1;j<=color;j++){
                    if(judge(i,j)){
                        col[i]=j; 
                        if(dfs(num+1,color))
                            return true;
                    }
                }
                vis[i]=0;
            }
        }
        return false;
    }
    int main()
    {
        while(scanf("%d",&n),n){
            memset(graph,0,sizeof(graph));
            for(int i=0;i<n;i++){
                cin>>ch;for(int j=2;j<strlen(ch);j++)
                    graph[ch[0]-'A'][ch[j]-'A']=1;
            }
            for(int i=1;i<=4;i++){
                memset(vis,0,sizeof(vis));
                if(dfs(1,i)){
                    if(i==1)
                        printf("1 channel needed.
    ");
                    else 
                        printf("%d channels needed.
    ",i);
                    break;
                }
            }
        }
    }

    暴力搜索

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    bool graph[30][30];
    char ch[30];
    int col[30],colornum;
    int n,mincolor;
    bool judge(int x,int y)
    {
        for(int i=0;i<n;i++){
            if(graph[x][i])
                if(col[i]==y) return false;
        }
        return true;
    }
    bool flag;
    void dfs(int i)
    {
        if(flag) return;
        if(i==n){//剪枝 
            mincolor=colornum;
            flag=1;
        }//判断用过的颜色里是否有可用的
        for(int j=1;j<=colornum;j++){
            if(judge(i,j)){
                col[i]=j;
                dfs(i+1);
                col[i]=0;//还原到dfs(i+1)之前的状态,因为可能还可以染其他颜色 
            }
        }
        colornum++;//上面颜色都不行的话再选用一种新的颜色
        col[i]=colornum;
        dfs(i+1);
        col[i]=0;//还原到dfs(i+1)之前的状态 
        colornum--;//还原,因为i都没被染色,所以新加的颜色肯定要退回去
    }
    int main()
    {
        while(scanf("%d",&n),n){
            memset(graph,0,sizeof(graph));
            for(int i=0;i<n;i++){
                cin>>ch;
                for(int j=2;j<strlen(ch);j++)
                    graph[ch[0]-'A'][ch[j]-'A']=1;
            }
            flag=0,colornum=1;
            memset(col,0,sizeof(col));
            dfs(0);//注意 不是dfs(1),因为第一个点的编号为0 
            if(mincolor==1)
                printf("1 channel needed.
    ");
            else
                printf("%d channels needed.
    ",mincolor);
        }
    }
  • 相关阅读:
    如何设计一个安全的对外接口?
    Java架构师必须知道的 6 大设计原则
    Spring Boot 如何快速改造老项目?
    Java 类中可以覆盖静态方法吗?
    Dubbo 的心跳设计,值得学习!
    在滴滴和头条干了 2 年后端开发,太真实…
    别乱提交代码了,看下大厂 Git 提交规范是怎么做的!
    3种骚操作,教你查看 Java 字节码!
    sysbench测试服务器性能
    mysql DDL时出现的锁等待状态
  • 原文地址:https://www.cnblogs.com/freinds/p/6404746.html
Copyright © 2011-2022 走看看