CF1483D-Useful Edges
题目大意
有一个 \(n\) 个结点的无向加权图,以及 \(q\) 个三元组,\((u,v,l)\) ,其中 \(u\) , \(v\) 是顶点,\(l\) 是正整数。
如果存在至少一个三元组和一个具有以下特性的路径(不一定简单),则边 \(e\) 被称为 有用。
· 这条路径的端点是 \(u\) 和 \(v\)。
· \(e\) 是这条路径的一条边。
· 这条路径上所有边的权重之和不超过 \(l\) 。
求这张图中有用边的数量。
题解
设城市 \(u\) 到 城市 \(v\) 的路径长度为 \(e[u][v]\) ,最短距离为 \(d[u][v]\) ,时间预算为 \(l[u][v]\) 。
根据题意,如果 \(i \to j\) 为 城市\(u\) 和城市 \(v\) 间的重要路径,则满足 \(d[u][i]+e[i][j]+d[j][v]\le l[u][v]\) 。
直接枚举 \(u,v,i,j\) 是 \(O(n^4)\) 的,显然不可以接受,于是考虑优化。一般来说,对于满足这样的不等关系的式子,我们可以通过减少未知量来降低复杂度。
在此,我们不妨移项,将上式转变为 \(e[i][j]+d[j][v]\le l[u][v]-d[u][i]\) 。这样可以只进行三方的枚举,就能分别求出不等号两边的量了。
我们可以先枚举 \(u,v,i\) 预处理出不等号的右边,注意是 \(\le\) ,所以要使不等号右边的值最大。然后再枚举 \(i,j,v\) ,判断是否符合条件即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ls(p) (p << 1)
#define rs(p) (ls(p) ^ 1)
typedef pair<int, int> pii;
const int INF = 1e16;
const int N = 605;
bool vis[N][N];
int d[N][N], w[N][N], l[N][N];
pii e[N * N];
inline int read();
inline void solve()
{
int n = read(), m = read();
memset(d, 0x3f, sizeof(d));
memset(w, 0x3f, sizeof(w));
for (int i = 1; i <= n; ++i)
d[i][i] = w[i][i] = 0;
for (int i = 1; i <= m; ++i)
{
auto &[u, v] = e[i];
u = read(), v = read();
w[u][v] = w[v][u] = d[u][v] = d[v][u] = read();
}
for (int k = 1; k <= n; ++k)
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
int q = read(), ans = 0;
while (q--)
{
int u = read(), v = read();
l[u][v] = l[v][u] = read();
}
for (int u = 1; u <= n; ++u)
{
for (int i = 1; i <= n; ++i)
{
int mx = -1e18;
for (int v = 1; v <= n; ++v)
{
mx = max(mx, l[u][v] - d[i][v]);
}
for (int j = 1; j <= n; ++j)
{
if (d[u][j] + w[j][i] <= mx)
vis[i][j] = 1;
}
}
}
for (int i = 1; i <= m; ++i)
{
auto [u, v] = e[i];
if (vis[u][v] || vis[v][u])
ans++;
}
printf("%lld\n", ans);
}
signed main()
{
int T = 1;
while (T--)
solve();
return 0;
}
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}

浙公网安备 33010602011771号