CF505B Mr. Kitayuta's Colorful Graph 题解
\(\textbf{\textit{Problem}}\)
给定 \(n\) 个点,\(m\) 条边的无向图,每条边有颜色 \(c_i\),共有 \(q\) 组询问 \((u,v)\),问题为满足下面条件的颜色数量:在 \(u,v\) 之间的所有路径中,存在一条路径,使得这条路径上所有边的颜色都是这个颜色。
\(1\le n,m,q\le 100\),\(1\le c_i\le m\)。
\(\textbf{\textit{Idea}}\)
注意到 \(n,m\le 100\) 的数据范围,于是我们可以想到:对于每一次询问,直接从 \(u\) 开始做 DFS,求出到每个节点的答案。
现在问题在于:如何计算答案?我们可以在 DFS 的过程中对每个节点存储一个 \(book_{i,j}\),表示所有到节点 \(i\) 的路径中,是否存在某一条路径上所有边的颜色均为 \(j\)。则很容易想到 \(book\) 的转移方程:(下面 \(u\) 表示当前节点,\(v\) 表示转移的节点,\(c\) 表示连接 \(u,v\) 的边的颜色)
如果直接对每条端点相同但颜色不同的边做上面的转移,我们会发现节点的访问标记会很混乱(因为存在一个节点被多次更新的情况),于是我们考虑将所有端点相同但颜色不同的边并在一起,将每条边的颜色 \(c\) 改为该条边并后表示的颜色集合 \(C\)。上面的转移方程就可以改成:(\(C\) 表示连接 \(u,v\) 的边的颜色集合)
最后答案显然就是 \(book_{v,i}\) 中值为 \(\texttt{true}\) 的位数了。
让我们分析一下时间复杂度:对于 \(q\) 次询问,每次做 DFS(时间复杂度为 \(\mathcal O(n+m)\)),每次 DFS 过程中需要进行 \(\mathcal O(m)\) 的转移,因此时间复杂度为 \(\mathcal O(qm(n+m))\),在本题中 \(n,m,q\le 100\) 的数据范围下完全可以通过。
\(\textbf{\textit{Code}}\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int N = 105, M = 205;
int n, m, q, u, v;
bool book[N][M], col[N][N][M];
vector<int> g[N];
void dfs(int x) {
for(int y : g[x]) {
bool flag = false;
for(int i = 1; i <= m; i++) {
if((book[x][i] && col[x][y][i]) && !book[y][i]) flag = true;
book[y][i] |= (book[x][i] && col[x][y][i]);
}
if(!flag) continue;
dfs(y);
}
}
void solve() {
cin >> n >> m;
for(int i = 1; i <= m; i++) {
int u, v, w; cin >> u >> v >> w;
g[u].push_back(v), g[v].push_back(u);
col[u][v][w] = col[v][u][w] = true;
}
cin >> q;
while(q--) {
cin >> u >> v;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
book[i][j] = (i == u ? true : false);
dfs(u);
int ans = 0;
for(int i = 1; i <= m; i++) ans += book[v][i];
cout << ans << endl;
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while(T--) solve();
return 0;
}

浙公网安备 33010602011771号