首页 > 其他 > 详细

PKU 1129

时间:2017-02-16 13:22:55      阅读:258      评论:0      收藏:0      [点我收藏+]

题目大意建模:

一个有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.\n");
                else 
                    printf("%d channels needed.\n",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.\n");
                else 
                    printf("%d channels needed.\n",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.\n");
                else 
                    printf("%d channels needed.\n",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;
        }
    }
    colornum++;//上面不行的话再选用一种新的颜色
    col[i]=colornum;
    dfs(i+1);
    col[i]=0;//及时清除标记
    colornum--;
}
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.\n");
        else
            printf("%d channels needed.\n",mincolor);
    }
}

PKU 1129

原文:http://www.cnblogs.com/freinds/p/6404746.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!