codeforces 1482 F. Useful Edges(思维+最短路)

传送门

题意:

给出一个 n n n个节点的无向带权图, ( n ≤ 600 ) (n \leq 600) (n600) ,和 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]ldis[u][i]

那么我们只需枚举 i , j , v i,j,v i,j,v​​ , 对于每个 v v v​ ,我们只需预先维护出最大的 l − d i s [ u ] [ i ] l-dis[u][i] ldis[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);
}
posted @ 2021-08-17 22:05  TheBestQAQ  阅读(64)  评论(0)    收藏  举报