解题思路:针对每一个字母,可以定义两个数组使其与连续的整数形成相互映射。接着定义两个vector,根据输入的连接形成一一对应关系,即同一个下标i,vector a[i]与b[i]相连。接着枚举排列,遍历vector得到每一个排列的带宽,并更新最小总带宽。
技巧学习:
1.双映射的巧妙应用,每一个字母用整数与之对应(我们并不需要直到每个字母具体对应哪一个整数)
2.使用双数组形成一一对应关系,无需特别存储某个字母与其他多个字母相连的状态。
3.添加pos数组记录数字对应的位置。
具体查看下面的代码。
题目大意:给出一些点(A,B,C,D...),以及所有必须相连的两点,代表这些点的字母可以组成不同的排列。然后每个排序中,遍历每个点及其相连关系,找出连接距离(即在排列中的位置差)的最大值,然后在所有排列中找出连接所需最短的。
Sample input
A:FB;B:GC;D:GC;F:AGH;E:HD
#
Sample output
A B C F G D H E -> 3
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
char a[300],letter[300];
int id[300];
while(scanf("%s",a)!=EOF)
{
int len=strlen(a),p=0,q=0,n=0;
for(char ch='A';ch<='Z';ch++)
{
if(strchr(a,ch)!=NULL) //使字符与数字形成双映射
{
id[ch]=n++;
letter[id[ch]]=ch;
}
}
vector<int> u,v;
while(1)
{
if(q>=len) break; //不能直接写q==len,可能存在q直接跳过len的情况
while(p<len&&a[p]!=':') p++; //找到:位置
//if(p==len) break;
while(q<len&&a[q]!=';') q++; //找到;位置
for(int i=p+1;i<q;i++) //遍历中间元素,使得一一对应
{
u.push_back(id[a[p-1]]);
v.push_back(id[a[i]]);
}
p++;q++;
}
int P[300],POS[300],best[300];
for(int i=0;i<n;i++) P[i]=i;
int ans=n;
do{ //找出每一种排列的带宽
for(int i=0;i<n;i++) POS[P[i]]=i; //巧妙地记录字母位置
int bandwidth=0;
for(int i=0;i<u.size();i++)
{
bandwidth=max(bandwidth,abs(POS[u[i]]-POS[v[i]]));
}
if(bandwidth<ans) //更新最小总带宽
{
ans=bandwidth;
memcpy(best,P,sizeof(int)*n);
}
}while(next_permutation(P,P+n));
for(int i=0;i<n;i++)
printf("%c ",letter[best[i]]);
printf("-> %d\n",ans);
}
return 0;
}