递归回溯 UVa140 Bandwidth宽带
本题题意:寻找一个排列,在此排序中,带宽的长度最小(带宽是指:任意一点v与其距离最远的且与v有边相连的顶点与v的距离的最大值),若有多个,按照字典序输出最小的哪一个。
解题思路:
方法一:由于题目说结点的个数最多是8个,所以,最先想到的方法是暴力枚举,将所有的结点全排列,然后找到宽带长度最小的那一个,此方法不会超时。
方法二:利用回溯法,将所有肯能的情况都遍历一遍,保存目前最短的宽带的长度minn,若当前的宽带长度大于minn,就进行剪枝,此题要注意,此题的结点不一定是从A开始的,所以要建立字母的映射,保存结点,同是注意输入时空格的处理。
暴力枚举的代码:
1 #include<stdio.h> 2 #include<math.h> 3 #include<string.h> 4 #include<algorithm> 5 #include<iostream> 6 using namespace std; 7 char str[100]; 8 int a[30][30],b[10],c[10][10],visit[10]; 9 int main(){ 10 // freopen("in.txt","r",stdin); 11 // freopen("out.txt","w",stdout); 12 while(gets(str)){ 13 memset(visit,0,sizeof(visit)); 14 memset(a,0,sizeof(a)); 15 memset(b,0,sizeof(b)); 16 memset(c,0,sizeof(c)); 17 if(str[0]=='#') break; 18 else{ 19 for(int i=0;i<strlen(str);){ 20 if(str[i]==' '){ 21 i++; 22 continue; 23 } 24 int t=str[i++]-'A'+1; 25 while(str[i]==' '){i++;} 26 i++; 27 while(i<strlen(str)){ 28 if(str[i]==' '){ 29 i++; 30 continue; 31 } 32 if(str[i]==';'){ 33 i++; 34 break; 35 } 36 int k=str[i++]-'A'+1; 37 a[t][k]=1; 38 a[k][t]=1; 39 } 40 } 41 } 42 int num=0; 43 for(int i=0;i<30;i++){ 44 int sum=0; 45 for(int j=0;j<30;j++){ 46 sum=sum+a[i][j]; 47 } 48 if(sum){b[num++]=i;} 49 } 50 int minn=7; 51 do{ 52 int maxx=0; 53 for(int i=0;i<num;i++){ 54 for(int j=1;j<=26;j++){ 55 if(a[b[i]][j]){ 56 for(int k=i+1;k<8;k++){ 57 if(b[k]==j) maxx=max(maxx,k-i); 58 } 59 } 60 } 61 } 62 if(!visit[maxx]){ 63 for(int i=0;i<num;i++){ 64 c[maxx][i]=b[i]; 65 } 66 visit[maxx]=1; 67 } 68 minn=min(minn,maxx); 69 }while(next_permutation(b,b+num)); //全排列函数。耗时,但是节省代码的长度时可用 70 for(int i=0;i<num;i++){ 71 printf("%c ",c[minn][i]+'A'-1); 72 } 73 printf("-> %d\n",minn); 74 } 75 return 0; 76 }
递归回溯的代码:
1 #include<stdio.h> 2 #include<math.h> 3 #include<string.h> 4 #include<algorithm> 5 #include<iostream> 6 using namespace std; 7 char str[100]; 8 int minn,maxx,num; 9 int a[30][30],b[10],c[10],visit[30],goal[10]; 10 11 12 void dfs(int n,int maxx){ 13 if(n==num){ 14 minn=maxx; 15 memcpy(goal,c,sizeof(c)); 16 return; 17 } 18 for(int i=0;i<num;i++){ 19 if(!visit[b[i]]){ 20 visit[b[i]]=1; 21 c[n]=b[i]; 22 int w=0; 23 for(int j=0;j<n;j++){ 24 if(a[b[i]][c[j]]){ 25 w=n-j; 26 break; 27 } 28 } 29 int max_w=max(maxx,w); 30 if(max_w<minn){ 31 dfs(n+1,max_w); 32 } 33 visit[b[i]]=0; 34 } 35 } 36 } 37 38 int main(){ 39 // freopen("in.txt","r",stdin); 40 // freopen("out.txt","w",stdout); 41 while(gets(str)){ 42 memset(visit,0,sizeof(visit)); 43 memset(a,0,sizeof(a)); 44 memset(b,0,sizeof(b)); 45 memset(c,0,sizeof(c)); 46 if(str[0]=='#') break; 47 else{ 48 for(int i=0;i<strlen(str);){ 49 if(str[i]==' '){ 50 i++; 51 continue; 52 } 53 int t=str[i++]-'A'+1; 54 while(str[i]==' '){i++;} 55 i++; 56 while(i<strlen(str)){ 57 if(str[i]==' '){ 58 i++; 59 continue; 60 } 61 if(str[i]==';'){ 62 i++; 63 break; 64 } 65 int k=str[i++]-'A'+1; 66 a[t][k]=1; 67 a[k][t]=1; 68 } 69 } 70 } 71 num=0; 72 for(int i=0;i<30;i++){ 73 int sum=0; 74 for(int j=0;j<30;j++){ 75 sum=sum+a[i][j]; 76 } 77 if(sum){b[num++]=i;} 78 } 79 minn=8; 80 maxx=0; 81 dfs(0,0); 82 for(int i=0;i<num;i++) 83 printf("%c ",goal[i]+'A'-1); 84 printf("-> %d\n",minn); 85 86 } 87 return 0; 88 }
提供几组测试数据:
A:FB;B:GC;D:GC;F:AGH;E:HD
A:FB;B:GC;D:GC;F:AGH;E:H
A:B;B:C;C:D;D:E;E:F;F:G;G:H
A:B;B:C;C:D;D:E;E:F;F:G;G:H;H:A
A:B;B:CE;C:D;D:E;E:F;F:G;G:H;H:A
A:B;B:CE;C:DG;D:E;E:F;F:G;G:H;H:A
A:BCDEFGH;B:ACDEFGH;C:ABDEFGH;D:ABCEFGH;E:ABCDFGH;F:ABCDEGH;G:ABCDEFH;H:ABCDEFG
#
答案:
A B C F G D H E -> 3
C D B G A F E H -> 2
A B C D E F G H -> 1
A B H C G D F E -> 2
C D B E A F H G -> 2
A B H C E G D F -> 3
A B C D E F G H -> 7