例题2:POJ 2570,某条道路由一些公司修建,修建道路的公司可以提供这条路上的连通,如第一个测试数据中,从1到2有a,b,c三个公司可以提供路径,现给你任意的两个地点,问有哪些公司可以提供路径。
这个题的难点就是给你的字符串如何存储,我们用map[u][v]表示u到v可以由哪些公司提供路径。初始化为0,那么它的二进制的每一位都为0,用0~26的位置表示a~z是否可以提供路径,可以则设为1。如图输入的字符串为abc,那么可以存储最后三位都为1,其余位不存在的设为0,这个时候map[i][j]转化为10进制就为7。
问题就是怎样把最后的三位改为1,可以利用位运算中的与(|)操作,如果是a则左移0位,如果是b则左移1位...z则左移25位。然后不断取与运算,利用与的性质只要有一个为1这个数就为1。
如:字符串s=abc,开始map[u][v]=0;遇到a时,取与map[u][v]|=1<<(s[0]-'a'),将最后一位变为1,表示a公司可以提供路径,同样处理,可以得到map[u][v]=(111)2=7。
map得到之后,根据Floyd算法,从i到j可以经过某一点k,那么只需取(&)运算(同1才为1),比方说:
从1到3,可以经过2,从1到2,可以由abc三个公司提供,从2到3可以由ad提供,我们知道满足条件的只有a,怎么得到结果:
abc 0 1 1 1
ad &1 0 0 1
-----------------
0 0 0 1 ----->得到了公共值为a。
如果还有一条路径,如1到3直接有一个b,这样我们可以知道从1到3可以由ab提供,这个时候可以取(|)运算。
a 0 1
b | 1 0
-----------
1 1 ------>得到最终结果ab。
运算过程为:map[i][j] | =(map[i][k] & map[k][j]) 。最终结果从i到j只需要看map[i][j]的二进制中的哪一位为1即可。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAX=210; #define CLR(arr,val) memset(arr,val,sizeof(arr)) int map[MAX][MAX]; int Chg(char *s) //将字符串转换为二进制形式存储 { int m=0; for(int i=0;i<strlen(s);i++) m|=1<<(s[i]-'a'); return m; } void Floyd(int n) { for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) map[i][j]|=(map[i][k]&map[k][j]); } int main() { int n,u,v; char s[50]; while(scanf("%d",&n),n) { CLR(map,0); while(scanf("%d%d",&u,&v),u+v) { scanf("%s",s); map[u][v]=Chg(s); } Floyd(n); while(scanf("%d%d",&u,&v),u+v) { int flag=1; for(int i=0;i<26;i++) if(map[u][v]&(1<<i)) { printf("%c",i+'a'); flag=0; } if(flag) printf("-"); printf("\n"); } printf("\n"); } return 0; }
题2:Tyvj 1423(拉绳子)
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; const int MAX=110; const int Inf=1000010; int n,m,map[MAX][MAX]; void Floyd() { for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(map[i][j]>map[i][k]+map[k][j]) map[i][j]=map[i][k]+map[k][j]; } int main() { int u,v; scanf("%d%d",&n,&m); for(int i=0;i<=n;i++) { fill(map[i],map[i]+MAX,Inf); map[i][i]=0; } for(int i=0;i<m;i++) { scanf("%d%d",&u,&v); map[u][v]=map[v][u]=1; } Floyd(); int max=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(max<map[i][j]) max=map[i][j]; printf("%d\n",max); return 0; }