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
#include<iostream>
#include<vector>
using namespace std;
#define MAXN 110
#define INF 0x3f3f3f3f;
int graph[MAXN][MAXN];//建立圖
int cun[MAXN][MAXN];//儲存第幾個教師有誰誰誰
int cnt[MAXN]={0};//記錄每個教室的人數
int res=INF;//假設需要一個無窮多的教室
int n,m;//定義人數,以及認識的數目
void solve(int id,int num)//回溯搜尋,id表示當前安排的是第id的同學,num表示當前安排這個id同學的時時候已經用了多少個教室
{
        if(num>=res)//如果當前的教室方案已經超過以前的方案了,那麼就放棄返回
        return;
    if(id>n)//如果說id的同學的id>n說明全部的同學都安排完了
        {
        res=num;//如果執行到這一步說明res一定是.>num的,所以更新一下
        return;//返回
        }
    for(int i=0;i<num;i++)//掃描每一個已經存在的教室
    {
        int len=cnt[i];//取一下當前i教室的人數
        int c=0;//這個變量表示當前id的同學和這個教室的同學不認識的人數
        for(int j=0;j<len;j++)//掃描這個教室的每一個同學
        {
            if(graph[id][cun[i][j]]==0)//如果沒有關係
                c++;//加1
        }
        if(c==len)//如果全部不認識
        {
            cun[i][cnt[i]++]=id;//那麼id同學就進入這個教室,同時這個教室的人數+1
            solve(id+1,num);//那麼安排下一個教室
            cnt[i]--;//遞迴返回之後把這個同學在從這個教室分走,分到下幾個教室看看
        }
    }
    cun[num][cnt[num]++]=id;//如果全部教室都存在id認識的同學,那麼就把這個同學新開個教室
    solve(id+1,num+1);//遞迴下一個同學並且當前的教室數目+!
    cnt[num]--;//返回後移除這個同學看下上一個同學有沒有其他的選擇
}
int main()
{
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        graph[a][b]=1;
        graph[b][a]=1;//如果兩個人認識的話就可以標記成1,c++在陣列建立 的時候已經快速初始化
    }
    solve(1,0);//進入回溯更新最小的教室數目
    cout<<res;//輸入所有可能中的最小的答案
}