codeforces 1482 F. Useful Edges(思维+最短路)
题意:
给出一个 n n n个节点的无向带权图, ( n ≤ 600 ) (n \leq 600) (n≤600) ,和 q q q 个三元组 ( u , v , l ) (u,v,l) (u,v,l)。
若一条边满足以下条件,则称为好的:
1. 1. 1. 存在一个三元组,使得该边在 u u u到 v v v的路径上,
2. 2. 2. 且该路径的权值总和小于 l l l
求有多少条边是好的。
题解:
先考虑暴力枚举每条边和每个三元组判断,对于一条边 e i j e_{ij} eij ,和一个三元组 ( u , v , l ) (u,v,l) (u,v,l) ,设 d i s [ i ] [ j ] dis[i][j] dis[i][j] 两点之间的最短路
若这个条是好的,说明 d i s [ u ] [ i ] + e [ i ] [ j ] + d i s [ j ] [ v ] ≤ l dis[u][i]+e[i][j]+dis[j][v] \leq l dis[u][i]+e[i][j]+dis[j][v]≤l
复杂度为 O ( n 4 ) O(n^4) O(n4) ,考虑优化一下,将上述式子移项变为: e [ i ] [ j ] + d i s [ j ] [ v ] ≤ l − d i s [ u ] [ i ] e[i][j]+dis[j][v] \leq l-dis[u][i] e[i][j]+dis[j][v]≤l−dis[u][i]
那么我们只需枚举 i , j , v i,j,v i,j,v , 对于每个 v v v ,我们只需预先维护出最大的 l − d i s [ u ] [ i ] l-dis[u][i] l−dis[u][i] 即可
复杂度为 O ( n 3 ) O(n^3) O(n3)
代码:
#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=6e2+5;
const int inf=0x3f3f3f3f;
ll dis[MAXN][MAXN];
int e[MAXN][MAXN];
vector<pii> g[MAXN];
ll ma[MAXN];
int main()
{
int n,m;
scanf("%d%d", &n, &m);
memset(dis, inf, sizeof dis);
for (int i = 1; i <= m;i++)
{
int u, v,w;
scanf("%d%d%d", &u, &v, &w);
e[u][v] = e[v][u] = w;
dis[u][v] = dis[v][u] = w;
}
for (int i = 1; i <= n;i++)
dis[i][i] = 0;
int q;
scanf("%d", & q);
for (int i = 1; i <= q;i++)
{
int u, v, l;
scanf("%d%d%d", &u, &v, &l);
g[u].push_back({ v, l });
g[v].push_back({ u, l });
}
for (int k = 1; k <= n;k++)
{
for (int i = 1; i <= n;i++)
{
for (int j = 1; j <= n;j++)
{
dis[i][j] = min(dis[i][k] + dis[k][j], dis[i][j]);
}
}
}
int ans = 0;
for (int i = 1; i <= n;i++)
{
memset(ma, -inf, sizeof ma);
for (int v = 1; v <= n;v++)
{
for(auto it:g[v])
{
ma[v] = max(ma[v], it.second - dis[it.first][i]);
}
}
for (int j = i+1; j <= n;j++)
{
if(!e[i][j])
continue;
for (int v = 1; v <= n;v++)
{
if(e[i][j]+dis[j][v]<=ma[v]){
ans++;
break;
}
}
}
}
printf("%d\n", ans);
}

浙公网安备 33010602011771号