题目链接

Floyd+位运算

两点之间的公司用二进制表示,只取重叠的公司,用Floyd松弛边。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;

const int Maxn = 200+10;
const int INF = 0x3f3f3f3f;

int G[Maxn][Maxn];
char str[30];

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) {
               if(k == i || k == j) continue;
               if(i == j || !G[i][k] || !G[k][j]) continue;
               G[i][j] |= (G[i][k]&G[k][j]);
           }
       }
   }
}

int main(void)
{
   int n;
   while(scanf("%d", &n) != EOF) {
       if(!n) break;
       memset(G, 0, sizeof(G));
       int u, v;
       while(scanf("%d%d", &u, &v)) {
           if(u == 0 && v == 0) break;
           scanf("%s", str);
           int tmp = 0;
           for(int i = 0; i < strlen(str); ++i)
               tmp |= 1<<(str[i]-'a');
           G[u][v] = tmp;
       }
       floyd(n);
       while(scanf("%d%d", &u, &v)) {
           if(u == 0 && v == 0) break;
           int tmp = G[u][v];
           if(tmp == 0) {
               printf("-\n");
           } else {
               for(int i = 0; i < 26; ++i) {
                   if(((tmp>>i)&1) == 0) continue;
                   printf("%c", i+'a');
               }
               puts("");
           }
       }
       puts("");
   }
   return 0;
}