题目大意:
给一张图的结点连接, 对各个结点进行排列, 排列中的每一个点与存在连接的点的距离的最大值为带宽,求出使带宽最小的排列
题目要我们求出所有排列中,bandwidth最小的那个排列,并输出这个排列和这个bandwidth
解题思路:
利用回溯,一开始设带宽为元素个数,然后一个个元素加入排列,加入元素时与前面已经加入排列并与新加入的元素有连接(即flag2[][] == 1)的元素计算l,如果得到的值l已经大于或者等于目前带宽则直接跳出不用继续扩展
(思路一开始就很清晰,但一些细节需要注意,如在排列前先要排序,遇到带宽相同的排列时用先出现的那个)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int flag[27]; //记录是否访问过字母
int flag2[27][27];
int num;
char note[10]; // 记录一共哪些点
char mini[10]; //记录目前最小的排列
int minc; //当前最小的带宽
char now[10]; //当前排列
void dfs(int maxc, int nowc) {
if(nowc == num) {
if(maxc < minc) {
strcpy(mini, now);
minc = maxc;
}
}
int g = maxc;
for(int i = 0; i < num; i++) {
int a = note[i] - 'A';
maxc = g;
if(flag[a] == 0) {
int g = 0;
for(int j = 0; j < nowc; j++) {
if(flag2[a][now[j]-'A'] == 1) {
int l = nowc - j;
if(l >= minc) {
g = 1;
break;
}
if(l > maxc)
maxc = l;
}
}
if(g == 0) {
flag[a] = 1;
now[nowc] = note[i];
dfs(maxc, nowc+1);
flag[a] = 0;
}
}
}
}
int main() {
char p;
num = 0;
memset(flag, 0, sizeof(flag));
memset(flag2, 0, sizeof(flag2));
p = getchar();
while(p != '#') {
getchar();
char c;
if(flag[p-'A'] == 0) {
flag[p-'A'] = 1;
note[num] = p;
num++;
}
while(1) {
c = getchar();
if(c == ';' || c == '\n')
break;
flag2[p-'A'][c-'A'] = 1;
flag2[c-'A'][p-'A'] = 1;
if(flag[c-'A'] == 0) {
flag[c-'A'] = 1;
note[num] = c;
num++;
}
}
if(c == '\n') {
sort(note, note+num);
minc = num;
memset(flag, 0, sizeof(flag));
dfs(0, 0);
for(int i = 0; i < num; i++)
cout << mini[i] << ' ';
printf("-> %d\n", minc);
memset(flag, 0, sizeof(flag));
memset(flag2, 0, sizeof(flag2));
num = 0;
}
p = getchar();
}
return 0;
}