標籤:floyd 位元運算
題意:一些公司決定搭建一些光纖網路,單向的,如果從第一點到第二點,有ab兩個公司可以搭建,第二點到第三點有ac兩個公司可以搭建,第一點到第三點有d公司可以搭建,則第一點到第三點有a、d兩個公司可以搭建,a是通過第二點,d是直接連接兩點。現在給你這麼一個光纖網路,問某兩點之間有哪些公司可以搭建起網路。
首先這題是個多源點的,有點像最短路的思想,如果讓我做我肯定硬著頭皮找相同的字母,不過我看到圖論書裡的想法很好,就寫上來了。
因為公司是用一個小寫字母來標識的,且每個公司的標識互不相同,也就是說最多隻有26個公司,因此,可以用整數中的二進位位來表示每個公司,通過二進位位元運算來實現集合的“或”運算和“與”運算。
如果第一點到第二點有a、b、c三個公司,則可用“00000000000000000000000000000111”來表示,第二點到第三點有a、d兩個公司,則可用“00000000000000000000000000001001“來表示。所以如果用edge數組表示某兩點之間的公司,就可以這麼更新:
edge[i][j] |= edge[i][k] & edge[k][j]。
然後是輸入輸出的處理,在讀入字串後,要用邏輯左移存入到edge數組中:edge[a][b] = 1 << (s[i]-‘a‘)
輸出的處理,枚舉字元ch從‘a’到‘z’,如果edge[a][b]&(1<<ch-‘a‘)為1,則表示edge[a][b]所代表的集合中包含ch公司,則輸出
如果edge[a][b]==0,說明a、b之間沒有公司了
二進位和位元運算真是好東西
#include<cstring>#include<string>#include<fstream>#include<iostream>#include<iomanip>#include<cstdio>#include<cctype>#include<algorithm>#include<queue>#include<map>#include<set>#include<vector>#include<stack>#include<ctime>#include<cstdlib>#include<functional>#include<cmath>using namespace std;#define PI acos(-1.0)#define MAXN 510#define eps 1e-7#define INF 0x7FFFFFFF#define seed 131#define ll long long#define ull unsigned ll#define lson l,m,rt<<1#define rson r,m+1,rt<<1|1int n;int edge[MAXN][MAXN];char s[30];void floyd(){ int i,j,k; for(k=1;k<=n;k++){ for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ edge[i][j] |= edge[i][k] & edge[k][j]; } } }}int main(){ int i,j; int a,b; while(scanf("%d",&n),n){ memset(edge,0,sizeof(edge)); while(scanf("%d%d",&a,&b),a||b){ scanf("%s",s); int l = strlen(s); for(i=0;i<l;i++){ edge[a][b] |= 1 << (s[i]-'a'); } } floyd(); while(scanf("%d%d",&a,&b),a||b){ for(i=0;i<=26;i++){ if(edge[a][b]&(1<<i)) printf("%c",'a'+i); } if(!edge[a][b]) printf("-"); printf("\n"); } printf("\n"); } return 0;}