CF677DIV3-G:最短路,暴力

题目大意:

给你一张图,有 k k k个点对 ( u i , v i ) (u_i,v_i) (ui,vi)。令 d ( i , j ) d(i,j) d(i,j)代表 i , j i,j i,j之间的最短路。

你现在可以使一条边的边权为0.问你最小的 ∑ i = 1 k d ( u i , v i ) \sum_{i=1}^{k}d(u_i,v_i) i=1kd(ui,vi)

n , m , k ≤ 1000 n,m,k \leq 1000 n,m,k1000

题目思路:

先对每个点跑dij预处理出最短路矩阵: d i s t ( i , j ) dist(i,j) dist(i,j)

然后因为只是一条边 = 0.它是否能更新一个点对 ( u , v ) (u,v) (u,v)的最短路。就是求 一定经过该条边的最短路 是否比原本最短路更短

令这条边的两个点为 a , b a,b a,b.那么一定经过该点的最短路是 m i n ( d i s t [ u ] [ a ] + d i s t [ b ] [ v ] , d i s t [ u ] [ b ] + d i s t [ a ] [ v ] ) min(dist[u][a]+dist[b][v] , dist[u][b]+dist[a][v]) min(dist[u][a]+dist[b][v],dist[u][b]+dist[a][v]) (两种走法)

知道这个trick之后这题就没了

所以枚举边 = 0,然后点对最短路累加更新答案即可.

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
const int maxn = 1005;
const int inf = 1e8;
int dp[maxn][maxn];
int n , m , k;
vector<pii> e[maxn];
vector<pii> Q;
struct Node
{
    int id , dis;
    bool operator < (const Node & a) const
    {
        return dis > a.dis;
    }
};
void dij(int dist[] , int s)
{
    priority_queue<Node> q;
    int book[maxn];
    for (int i = 1 ; i <= n ; i++){
        dist[i] = inf;
        book[i] = 0;
    }
    dist[s] = 0;
    q.push({s , 0});
    while (q.size()){
        Node tmp = q.top();q.pop();
        int id = tmp.id;
        if (book[id]) continue;
        book[id] = 1;
        for (auto & g :e[id]){
            int v = g.first , w = g.second;
            if (dist[v] == -1 || dist[v] > dist[id] + w){
                dist[v] = dist[id] + w;
                q.push({v , dist[v]});
            }
        }
    }

}
vector<pii> edge;
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m >> k;
    for (int i = 1 ; i <= m ; i++){
        int x , y , z; cin >> x >> y >> z;
        e[x].pb (mp(y , z));
        e[y].pb (mp(x , z));
        edge.pb(mp(x , y));
    }
    for (int i = 1 ; i <= k ; i++){
        int x , y; cin >> x >> y;
        Q.pb(mp(x , y));
    }
    for (int i = 1 ; i <= n ; i++) dij(dp[i] , i);
    int ans = 2e9;
    for(auto p : edge){
        int res = 0;
        for (auto g : Q){
            res += min (dp[g.first][g.second] ,
                        min(dp[g.first][p.first] + dp[p.second][g.second] ,
                            dp[g.first][p.second] + dp[p.first][g.second]));
        }
        ans = min (ans ,res);
    }
    cout << ans << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值