題目描述
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
分析:本題實現主要方法還是DFS,但處理不好的話容易超時。所以還要額外附帶剪枝。
基本思路爲先將考生之間的相互關係用鄰接矩陣標記,然後從第一個學生開始,遍歷所有可行的考場。每個考場以及座位號(標記某個考生已在某個考場的某個座位就坐,其他考生不允許坐在這裏)如果這個考生在這個考場可以坐下,那麼就在這個考場的座號上標記,並回溯下一個考生。如果所有考場都不適合該考生那麼就新開一個考場,讓這個學生在這裏坐下。
總之這個題細節很多,要仔細分析。
#include<cstdio>
int Map[105][105];//Map來描述考生之間的關係
int status[105][105];//status用來描述每個考場和座位的佔位情況 前者表示考場號,後者表示座位號
int n,m,minsum,a,b;
void dfs(int xs,int kc){ //xs表示第幾個學生,kc表示第幾個考場
if(kc >= minsum) //剪枝,如果當前方案的已分配考場數大於等於最優解,剪掉
return; //否則會運行超時
if(xs > n){ //如果所有學生都已分配 ,當前解與最優解比較,取最小值
if(kc<minsum)
minsum = kc;
return;
}
int j,k;
for(j=1;j<=kc;j++){ //對這個考生考慮所有可行的考場
k=1;
while(status[j][k] && !Map[xs][status[j][k]])//1.如果第j個考場的第k個座位未佔,佔用
k++; //如果第j個考場的第k個座位已佔,並且
//2.這個座位上的考生與要佔座的考生有一
//定關係,不再考慮。換下個考場
//3.如果第j個考場的第k個座位已佔,並且
//這個座位上的考生與要佔座的考生沒有
//關係,考慮下一個座位。
if(status[j][k]==0){ //這個判斷條件主要是爲上面第二條準備的
status[j][k] = xs; //佔座
dfs(xs+1,kc); //對下一個考生進行分配
status[j][k] = 0; //回溯,考慮下一個考場
}
}
status[kc+1][1]=xs; //如果所有考場,都不適合該考生,那就新開一個考場。
dfs(xs+1,kc+1);
status[kc+1][1]=0;
}
int main(){
scanf("%d",&n);//輸入考生數
scanf("%d",&m);//輸入關係數
minsum = n;
for(int i=1;i<=m;i++){
scanf("%d %d",&a,&b);
Map[a][b]=Map[b][a]=1;//將兩個考生的相互關係標記
}
dfs(1,0); //注意這裏剛開始不要分配考場,否則容易超時
printf("%d\n",minsum); //輸出最優解
}