qoj18375 Graph
给定图 \(G\),最小化删去边 \((s,t)\) 及 \((u,v)\) 后得到的图 \(G'\) 上 \(d'(s,t)+d'(u,v)\) 的最小值,其中 \(d'(x,y)\) 是点 \(x,y\) 在图 \(G'\) 上的距离。并计数取得最小值的方案数。
考虑只删一条边,答案为最小环的大小 \(-1\)。
同理,可得原问题的答案即为最小环的大小加次小环的大小 \(-2\)。
证明考虑,首先其显然为答案下界。
其次设最小环和次小环为 \(R_1,R_2\),删去的边 \(E_1\in R_1,E_2\in R_2\)。
若删去 \(E_1\) 使得 \(E_2\) 的贡献无法取得最小值 \(|R_2|-1\),必有 \(E_1\in R_2\)。
若对任意 \(E_1\) 均成立,必有 \(R_1\subset R_2\),而这对于简单环是不可能的。
考虑计数,我们首先枚举每条边 \(i\),找出包含该边的最小环 \(R_i\)。
对每条边 \(j\) 考虑。\(j\) 与 \(i\) 能否同时被选择,当且仅当存在一个环 \(R'\) 使得 \(|R'|=R_i\) 且 \(i\in R',j\notin R'\)。
为了快速断言这一点,我们对环 \(r'\) 计数,以及对包含边 \(j\) 的 \(r'\) 计数,通过维护两点间最短路的方案数不难实现。
取喜欢的模数哈希即可做到几乎正确判定。
最后枚举边 \(i,j\) 满足 \(|R_i|+|R_j|\) 取得全局最小值,且 \(i,j\) 可以同时取得。
时间复杂的 \(\mathcal O(n^2)\)。
#include <algorithm>
#include <iostream>
#include <vector>
#include <random>
#include <queue>
#include <unordered_set>
const int O = 1069313197;
auto incr = [](auto& x, auto&& y) { x += y, x -= (x >= O) * O; };
typedef unsigned long long u64;
u64 weight[5000];
inline void init() {
std::mt19937_64 rnd(5201314);
for(int i = 0; i < 5000; ++i) weight[i] = rnd();
}
inline void solve() {
int n, m;
std::cin >> n >> m;
std::vector<std::vector<int>> g(n);
struct st { int x, y, w; std::vector<bool> T; };
std::vector<st> edg(m);
for(int x, y, i = 0; i < m; ++i) {
std::cin >> x >> y, --x, --y;
g[x].emplace_back(y);
g[y].emplace_back(x);
edg[i].x = x, edg[i].y = y;
}
std::vector<int> ban(m);
std::unordered_set<u64> set;
int ans1 = 1e9, ans2 = 1e9;
for(int i = 0; i < m; ++i) {
auto& [x, y, w, T] = edg[i];
auto bfs = [&](int s, std::vector<int>& d, std::vector<int>& p) {
std::queue<int> q;
q.push(s), d[s] = 0, p[s] = 1;
while(!q.empty()) {
int u = q.front(); q.pop();
for(auto& v: g[u]) {
if((v==x && u==y) || (v==y && u==x)) continue;
if(d[v] == -1) d[v] = d[u] + 1, q.push(v);
if(d[v] == d[u] + 1) incr(p[v], p[u]);
}
}
};
std::vector<int> dx(n, -1), dy(n, -1), px(n), py(n);
bfs(x, dx, px), bfs(y, dy, py);
w = dx[y]; int p = px[y];
if(w == -1 || w > ans2) {
ban[i] = 1;
continue;
}
T.resize(m);
u64 hash = weight[i];
for(int j = 0; j < m; ++j) {
auto& [a, b, $1, $2] = edg[j];
if(j == i) continue;
T[j] = 1;
if((dx[a] + dy[b] + 1 == w && 1ll * px[a] * py[b] %O == p) ||
(dx[b] + dy[a] + 1 == w && 1ll * px[b] * py[a] %O == p))
T[j] = 0, hash ^= weight[j];
}
if(p > 1) {
ans1 = std::min(ans1, w);
ans2 = std::min(ans2, w);
} else if(!set.count(hash)) {
set.insert(hash);
if(w < ans1) ans2 = ans1, ans1 = w;
else if(w < ans2) ans2 = w;
}
}
int ans = 0;
for(int i = 0; i < m; ++i) {
if(ban[i] || edg[i].w > ans2) continue;
for(int j = i+1; j < m; ++j) {
if(ban[j]) continue;
if(edg[i].w + edg[j].w == ans1 + ans2 && edg[i].T[j] && edg[j].T[i]) {
++ans;
}
}
}
std::cout << ans1 + ans2 << ' ' << ans << "\n";
}
int main() {
init(), std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int t; std::cin >> t; while(t--) solve();
}
本文来自博客园,作者:CuteNess,转载请注明原文链接:https://www.cnblogs.com/CuteNess/p/22634960

浙公网安备 33010602011771号