蓝桥杯_ 历届试题 分考场 (图的着色问题)

        问题描述:存在一个无向图,要求给图中的点涂色,并且有线连接的点之间不能是同一种颜色。

        问题思路:回溯

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <stack>
#include <vector>
#include <queue>
#define ll long long
#define INF 0x3f3f3f3f

using namespace std;
const int MAXN = 110;
int graph[MAXN][MAXN];
int color[MAXN];
int n,m,num_col;

bool Judge(int x,int col)//判断当前情况下,这个点能比能是col这个颜色
{
    for(int i = 1;i <= n;i ++)
    {
        if(graph[i][x] && color[i] != 0 && color[i] == col )
            return false;
    }
    return true;
}
void Init()
{
    scanf("%d%d",&n,&m);//n边的条数,m点的个数
    int a,b;
    scanf("%d",&num_col);//能用的颜色数目
    memset(graph,0,sizeof(graph));//存图
    memset(color,0,sizeof(color));//每个点的颜色
    for(int j =0 ;j < n;j ++)
    {
        scanf("%d%d",&a,&b);
        graph[a][b] = graph[b][a] = 1;
    }
}
void Solve(int pos)
{
    if(pos == n)
    {
        for(int i =1 ;i <= m;i ++)
            printf("%d%c",color[i],i==m?'\n':' ');
        return ;
    }
    for(int i = 1;i <= num_col;i ++)
    {
        if(Judge(pos,i))
        {
            color[pos] = i;
            Solve(pos+1);
            color[pos] = 0;
        }
    }
}
int main()
{
    Init();
    Solve(1);
}

但是我们还有一个问题,就是如果给你了图的边和点,我们应该计算所需要最少的颜色呢?

我们有一个例题:

问题描述
  n个人参加某项特殊考试。
  为了公平,要求任何两个认识的人不能分在同一个考场。
  求是少需要分几个考场才能满足条件。
输入格式
  第一行,一个整数n(1<n<100),表示参加考试的人数。
  第二行,一个整数m,表示接下来有m行数据
  以下m行每行的格式为:两个整数a,b,用空格分开 (1<=a,b<=n) 表示第a个人与第b个人认识。
输出格式
  一行一个整数,表示最少分几个考场。
样例输入
5
8
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5
样例输出
4
样例输入
5
10
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
样例输出
5

因为这个问题的数据量很小,所以我们想到了回溯,在已知的状态下,然后去判断下一个学生是否可以在之前存在的教室,如果不可以的话,那么就新开一个教室。

因为这个题的时间限制,没有使用vector,所以程序理解起来可能会有一点麻烦。

#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>

using namespace std;

const int maxn = 110;
const int inf = 0x3f3f3f3f;
int gra[maxn][maxn];   //是否存在关系,存在关系就是1,不存在关系就是0
int cun[maxn][maxn];   //第一维度表示的是考场,二位度里面放的是这个考场里面的学生
//cun[1][1] = 2,cun[1][2] = 0;表示考场1里面第一个存在的人是2,然后后面一位是0,也就是不存在人了,那么这时的cun[1] = 1;表示的是考场里面人的数量
int cnt[maxn];         //是cun数组存的是学生的数量
int res=inf;
int n,m;
void solve(int id,int num){    //id表示学生,num表示当前考场的编号
    if(num>=res){              //当现在安排的数量已经大于了最小的教室数量的话,返回
        return;
    }
    if(id>n){                 //安排的学生已经大于所有的学生了,就是安排完所有的学生了已经
        res=min(res,num);
        return;
    }
    for(int i=1;i<=num;i++){   //首先看看之前的房间里面能不能放进去
        int sz=cnt[i];
        int jishu=0;      //得到的是和这个人不认识的人数
        for(int j=1;j<=sz;j++){
            if(gra[id][cun[i][j]]==0){
                jishu++;
            }
        }
        if(jishu==sz){   //如果这里面的学生都和现在遍历的都不认输
            cun[i][++cnt[i]]=id; //将这个学生存到这个考场中
            solve(id+1,num);
            cnt[i]--;
        }
    }
    //重新开一个房间
    cun[num+1][++cnt[num+1]]=id;  //没有的话就把它放到下一个教室里
    solve(id+1,num+1);
    --cnt[num+1];
}
int main(){
    scanf("%d%d",&n,&m);
    memset(gra,0,sizeof(gra));
    memset(cnt,0,sizeof(cnt));
    while(m--){
        int a,b;
        scanf("%d%d",&a,&b);
        gra[a][b]=gra[b][a]=1;
    }
    solve(1,0);
    printf("%d\n",res);
    return 0;
}



  • 14
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值