例题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;
}
#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;
}