Fiber Network ZOJ 1967(Floyd+二进制状态压缩)
Description
Now, service providers, who want to send data from node A to node B are curious, which company is able to provide the necessary connections. Help the providers by answering their queries.
Input
After the list of connections, each test case is completed by a list of queries. Each query consists of two numbers A, B. The list (and with it the test case) is terminated by A=B=0. Otherwise, 1<=A,B<=n, and they denote the start and the endpoint of the query. You may assume that no connection and no query contains identical start and end nodes.
Output
Sample Input
3
1 2 abc
2 3 ad
1 3 b
3 1 de
0 0
1 3
2 1
3 2
0 0
2
1 2 z
0 0
1 2
2 1
0 0
0
Sample Output
ab
d
-
z
-
题目意思:n个路由器,编号1-n,26个公司,编号a-z,路由器之间有一些有向边,边权为一个字符串,字符串由小写字母组成,表示字符串对应的公司能使这条边连通。现在给若干个查询,查询能使任意2个路由器连通的公司。输出公司号,若不存在公司则输出‘-’。
解题思路:本题并不是求最短路,但是却要用到Floyd算法求解最短路的思想。题目就是要求能使任意2个路由器连通的公司的集合,所以可以使用Floyd传递闭包建立联系。另外,在本题中需要很巧妙地处理公司集合,公司是一个小写字母标识,最多只有26个公司,这样可以使用整数二进制位代表每个公司实现集合的状态压缩。
例如,站点1到站点2连接的公司有集合{ ‘a’ , 'b' , 'c' },可以用“00000000000000000000000111”表示,
站点2到站点3连接的公司有集合{ ‘a’ , 'd' } ,可以用“00000000000000000000001001”表示,
这两个整数进行二进制与运算后得到“00000000000000000000000001”表示通过中间站点2,站点1到站点3的连接的公司是集合{ ‘ a ’ }。
floyd的本质是枚举中间节点k,使节点i到j的距离最大或最小。针对本题,是要求一个集合,使从i到j连通的公司,那么枚举k的时候,就要求保证i->k和k->j同时连通的公司,状态压缩的话,直接将dis[i][k]和dis[k][j]相与便是结果,这个结果要加到dis[i][j]上去,所以再和dis[i][j]相或。所以总的方程就是:
dis[i][j] = dis[i][j] | (dis[i][k]&dis[k][j])。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int dis[210][210]; 6 int n,m; 7 void Floyd() 8 { 9 int i,j,k; 10 for(k=1; k<=n; k++) 11 { 12 for(i=1; i<=n; i++) 13 { 14 for(j=1; j<=n; j++) 15 { 16 dis[i][j]|=(dis[i][k]&dis[k][j]); 17 } 18 } 19 } 20 } 21 int main() 22 { 23 int a,b,i; 24 int len; 25 char s[30]; 26 while(scanf("%d",&n)!=EOF) 27 { 28 if(n==0) 29 { 30 break; 31 } 32 memset(dis,0,sizeof(dis)); 33 while(scanf("%d%d",&a,&b)!=EOF) 34 { 35 if(a==0&&b==0) 36 { 37 break; 38 } 39 scanf("%s",s); 40 len=strlen(s); 41 for(i=0; i<len; i++) 42 { 43 dis[a][b]|=(1<<(s[i]-'a'));///逻辑左移s[i]-'a'位 44 } 45 } 46 Floyd(); 47 while(scanf("%d%d",&a,&b)!=EOF) 48 { 49 if(a==0&&b==0) 50 { 51 break; 52 } 53 if(dis[a][b]) 54 { 55 for(i=0; i<26; i++) 56 { 57 if(dis[a][b]&(1<<i))///如果dis[a][b]&(1<<i)!=0,说明dis[a][b]所代表的集合中包含公司'a'+i 58 { 59 putchar('a'+i); 60 } 61 } 62 } 63 else 64 { 65 putchar('-'); 66 } 67 putchar('\n'); 68 } 69 putchar('\n'); 70 } 71 return 0; 72 }