题意:给定n(n<=8)个节点的图和一个节点的排列,定义节点i的带宽为i和相邻节点在排列中的最远距离,整个图的带宽便是每个节点带宽的最大值,给定图G,求出让带宽最小的节点排列。
题解:因为数据范围不大,所以直接用next_permutation函数枚举每种情况,对每个排列ji其实进行计算,当得到的最大值比目前的最小值要大或者相等时就剪枝,(其实不剪也能过)。因为是输出最小字典序,所以要从最小的字典序开始用next_permutation函数,只记录第一次遇到新低时的字典序。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 30
using namespace std;
typedef long long ll;
int mp[maxn][maxn];
int vis[maxn],num[10];
int minn,cnt,pos[maxn],ans[10];
bool read(){
memset(vis,0,sizeof(vis));
memset(mp,0,sizeof(mp));
char ch='.';
while(ch!='\n'){
ch=getchar();
if(ch=='#') return false;
int id=ch-'A';
vis[id]=1;
ch=getchar();
while((ch=getchar())!=';'&&ch!='\n'){
int tmp=ch-'A';
vis[tmp]=1;
mp[id][tmp]=1;
mp[tmp][id]=1;
}
}
return true;
}
void solve(){
for(int i=0;i<cnt;i++){
pos[num[i]]=i;
}
int maxx=0;
for(int i=0;i<cnt;i++){
int u=num[i];
for(int j=0;j<maxn;j++){
if(mp[u][j]){
maxx=max(maxx,i<pos[j]?pos[j]-i:i-pos[j]);
if(maxx>=minn) return;
}
}
}
if(minn>maxx){
minn=maxx;
for(int i=0;i<cnt;i++) ans[i]=num[i];
}
}
int main(){
while(read()) {
cnt=0;
minn=10;
for(int i=0;i<maxn;i++)
if(vis[i]) num[cnt++]=i;
do{
solve();
}while(next_permutation(num,num+cnt));
for(int i=0;i<cnt;i++){
printf("%c ",(char)ans[i]+'A');
}
printf("-> %d\n",minn);
}
return 0;
}