题意:一个无向图包含 n 个点 m 条边,顶点编号从 1 到 n 。连接着顶点 ai 和顶点 bi的边的颜色为 ci 。之后有 q 个询问。每条询问有两个整数 ui 和 vi,找到满足下面条件的颜色个数:同一种颜色的路径连接顶点 ui 和顶点 vi。
题解:本题显然是让判断颜色的联通性,关于连通性的判断我们可以用并查集实现,只不过这里的并查集多了一个颜色属性,我们需要在并查集再开一维颜色属性。此外,本题其实是连通性的传递,涉及传递闭包且数据较小,所以可以直接使用floyd实现连通性的传递。
并查集AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
const int maxn=105;
int n,m,f[maxn][maxn];
int find_x(int x,int c) {
if(f[x][c]!=x) return f[x][c]=find_x(f[x][c],c);
else return x;
}
void unite(int x,int y,int c) {
int aa=find_x(x,c);
int bb=find_x(y,c);
if(aa!=bb)f[aa][c]=bb;
}
main() {
IOS;
int n,m;
cin>>n>>m;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
f[i][j]=i;
for(int i=1; i<=m; i++) {
int x,y,w;
cin>>x>>y>>w;
unite(x,y,w);
}
int t;
cin>>t;
while(t--){
int x,y,ans=0;
cin>>x>>y;
for(int i=1;i<=m;i++){
int aa=find_x(x,i);
int bb=find_x(y,i);
if(aa==bb)ans++;
}
cout<<ans<<endl;
}
}
Floyd_AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
int n,m,d[105][105][105];
void floyd() {
for(int k=1; k<=n; k++)//floyd的中间结点层枚举时一定要放在第一层
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
//for(int k=1; k<=n; k++)
for(int c=1; c<=m; c++)
if(d[i][k][c]&&d[j][k][c])d[i][j][c]=1;
}
main() {
IOS;
cin>>n>>m;
for(int i=1; i<=m; i++) {
int x,y,w;
cin>>x>>y>>w;
d[x][y][w]=1;
d[y][x][w]=1;
}
floyd();
int t;
cin>>t;
while(t--) {
int x,y,ans=0;
cin>>x>>y;
for(int i=1; i<=m; i++) {
if(d[x][y][i])ans++;
}
cout<<ans<<endl;
}
}