递归回溯 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

posted @ 2017-08-09 16:20  木子丘  Views(221)  Comments(0Edit  收藏  举报