全排列回溯剪枝。
题目数据很水。记录当前最小带宽,边回溯边计算当前序列最大的距离(也就是带宽),如果当前带宽超过了当前的最小带宽就剪枝。
注意下,数据读入时的字符串处理。
AC代码
#include<cstdio>
#include<cstring>
int G[26][26];
const char a[27]="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int n; //记录字母种类数
int v[26],ans[10],res[10],temp[10];
int hard=10;//最终结果
int turn(char c)
{
return strchr(a,c)-a;
}
void dfs(int cur,int k)
{
if(cur==n&&k<hard)
{
hard=k;
for(int i=0;i<n;++i)
{
ans[i]=temp[i];
}
return ;
}
for(int i=0;i<n;++i)
{
int ok=1;
for(int j=0;j<cur;j++)
{
if(temp[j]==res[i])
{
ok=0;
break;
}
}
if(ok)
{
for(int j=0;j<cur;++j)
{
if(G[temp[j]][res[i]])
{
if((cur-j)>k)
k=cur-j;
}
}
if(k<hard)
{
temp[cur]=res[i];
dfs(cur+1,k);
}
}
}
}
int main()
{
char s[150];
while(scanf("%s",s)==1&&s[0]!='#')
{
n=0,hard=10;
memset(v,0,sizeof(v));
memset(G,0,sizeof(G));
for(int i=0,j=0;;++j)
{
if(s[j]==';'||s[j]=='\0')
{
int x=turn(s[i]),y=i+2;
v[x]++;
while(y!=j)
{
int t=turn(s[y]);
G[x][t]=1;
G[t][x]=1;
++y;
v[t]++;
}
i=j+1;
}
if(s[j]=='\0')
break;
}
for(int i=0;i<26;++i)
{
if(v[i]) res[n++]=i;
}
// printf("%d\n",n); //打印字母个数
dfs(0,1);
for(int i=0;i<n;++i)
{
if(i==n-1)
printf("%c -> %d",'A'+ans[i],hard);
else printf("%c ",'A'+ans[i]);
}
printf("\n");
}
return 0;
}
如有不当之处欢迎指出!