给出一个图,找出其中的最小带宽的排列。具体要求见传送门:UVa140
这题有些小技巧可以简化代码的编写。
本题的实现参考了刘汝佳老师的源码,的确给了我许多启发,感谢刘老师。
思路:
建立双射关系:从字符A到字符Z遍历输入的字符串,用strchr函数将输入中出现的字符找出,并将找出的字符进行编号,用letter和id分别存储字符和对应的编号
降维:输入中给出的,是类似于邻接表形式的二维形式,如果我们用二维数据结构,将增加处理时对于输出细节的处理难度,用 2个 vector将输出降低到1维,简化了计算Bandwidth时的代码,实际上让我们更加有的放矢
存储必要信息——位置:数组pos每个下标代表字母编号,存储的是对应的位置下标,便于计算时寻找位置。
剪枝:减去不必要的计算(虽然对于本题而言不是必须的)
库函数的使用:memcpy,strchr,strlen,next_permutation的使用简化了代码,突出了逻辑部分。
#include<cstdio>
#include<vector>
#include<cstring>
#include<map>
//#include<sstream>
using namespace std;
const int maxn = 9 + 1, INF = 1000;
vector<int> G[maxn];
map<char, int> ID;
map<int, char> antiID;
int A[maxn];
int n;
int k;
int ans[maxn];
int pos[maxn];
//int node;
void dfs(int cur, int tmp) //tmp为解答树每条树枝特有的属性,为实现这种性质需将其作为每个递归内部定义变量,作为参数传递
{
if (cur > n) //递归终止条件必须有
{
if (k > tmp)
{
k = tmp;
memcpy(ans, A, sizeof(ans));
}
return;
}
for (int i = 0; i < n; i++)
{
if (pos[i] > -1) //重复出现
continue;
int cnt = 0;
for (int j = 0; j < G[i].size(); j++)
{
int& v = G[i][j];
if (pos[v] > -1)
{
/*for (int m = 0; m < cur; m++)
{
if (A[m] == v)
{
if ((cur - 1 - m) >= k) //剪枝
return;
if ((cur - 1 - m) > tmp)
tmp = (cur - 1 - m);
break;
}
}*/
if ((cur - 1 - pos[v]) >= k) //剪枝//用pos数组记录排列
return;
if ((cur - 1 - pos[v]) > tmp)
tmp = (cur - 1 - pos[v]);
cnt++;
}
}
if ((G[i].size() - cnt) >= k) //剪枝
//return;
continue; //注意回溯或剪枝对应的return或continue的选择使用
A[cur - 1] = i;
pos[i] = cur - 1;
dfs(cur + 1, tmp);
A[cur - 1] = -1; //全局变量在出口处修改
pos[i] = -1;
}
}
int main()
{
char input[1000];
while (scanf("%s", input) == 1 && input[0] != '#')
{
memset(ans, 0, sizeof(ans));
memset(A, -1, sizeof(A));
memset(pos, -1, sizeof(pos));
for (int i = 0; i < 8; i++)
G[i].clear();
n = 0;
for (char i = 'A'; i <= 'H'; i++)
{
if (strchr(input, i) != NULL) //输入处理,注意输入不一定从A开始,甚至不包含A
{
ID[i] = n;
antiID[n++] = i;
}
}
int len = strlen(input), p = 0, q = 0;
//vector<int> u, v; //建图方式
for (;;)
{
while (p < len && input[p] != ':') //输入处理
p++;
if (p == len)
break;
while (q < len && input[q] != ';')
q++;
for (int i = p + 1; i < q; i++)
{
G[ID[input[p - 1]]].push_back(ID[input[i]]);
G[ID[input[i]]].push_back(ID[input[p - 1]]);
}
p++; q++;
}
k = INF;
dfs(1, -1);
for (int i = 0; i < n; i++)
printf("%c ", antiID[ans[i]]);
if (n == 1)
printf("-> 0\n");
else
printf("-> %d\n", k);
}
}
/*int main() {
{
// 计算结点个数并给字母编号
int n = 0;
for (char ch = 'A'; ch <= 'Z'; ch++)
id[ch] = n++;
letter[id[ch]] = ch;
}*/
WA待改