1. 程式人生 > 其它 >G - Reducing Delivery Cost -最短路

G - Reducing Delivery Cost -最短路

G - Reducing Delivery Cost

題意:

給你n個點和m條邊以及每條邊的權值 允許讓一條邊的權值變成0 然後有q次詢問 求q次詢問的xi到yi的最小路徑和

思路:

顯然是最短路的題 但是直接套最短路模板 列舉每條免費的邊然後再dij每個點 來求 時間複雜度 是 n* m * k * log(m)會超時

所以就要考慮 先預處理每兩個點的最短路 用dis[x][y]儲存 後續再列舉每條邊 求最短路

對於一條免費的邊有兩種情況

  • 免費前後都不在最短路徑中 那麼就是沒有影響
  • 免費後在最短路徑中 最短路那麼就要取免費後更小的值(比較dis[i][j] , dis[i][x] + dis[y][j], dis[i][y] + dis[x][j] 取較小值)
#include <bits/stdc++.h> 
#include <queue>
#define ll unsigned long long
#define pi acos(-1)
#define FF ios::sync_with_stdio(false), cin.tie(0)
using namespace std;
const int mod = 1e9 + 7;
const int N = 1e6 + 10;
const int inf = 0x3f3f3f3f;
int  n, m, qq, dis[1010][1010];

struct node{
    int
to, w; }; vector<node> g[N]; vector<pair<int, int> >v; int vis[1010], inq[1010]; priority_queue<pair<int ,int>, vector<pair<int ,int> >, greater<pair<int ,int> > >q; //最短路演算法 void dij(int x){ //初始化 memset(vis, 0, sizeof(vis)); memset(inq, 0, sizeof
(inq)); dis[x][x] = 0;//自己到自己值為零 q.push(make_pair(dis[x][x], x)); inq[x] = 1;//記錄已在佇列中 while(!q.empty()){ pair<int, int>now = q.top(); q.pop(); if(vis[now.second]) continue; vis[now.second] = 1;//判斷是否已經訪問過 int from = now.second; for(int i = 0; i < g[from].size(); i++){ int to = g[from][i].to; int w = g[from][i].w;//注意寫法 不要用min函式 if(dis[x][to] > dis[x][from] + w){ dis[x][to] = dis[x][from] + w; if(!inq[to]) q.push(make_pair(dis[x][to], to)); } } } } int main() { FF; cin >> n >> m >> qq; for(int i = 1; i <= m; i++){ int x, y, w; cin >> x >> y >> w; g[x].push_back({y, w}); g[y].push_back({x, w}); } memset(dis, inf, sizeof(dis));//因為是取最小 所以一開始要很大 for(int i = 1; i <= n; i++){//預處理最短路 dij(i); } for(int i = 1; i <= qq; i++){ int a, b; cin >> a >> b; v.push_back(make_pair(a, b)); } int anss = inf; for(int i = 1; i <= n; i++){ for(int j = 0; j < g[i].size(); j ++){ int t = g[i][j].to; int ans = 0; for(int k = 0; k < v.size(); k++){ int from = v[k].first, to = v[k].second; //直接用ans+= 不要更新dis 不然會出錯 比大小的時候不要忘了是三個值比較 容易把dis[from][t]+dis[i][to]忘記 ans += min({dis[from][to], dis[from][i] + dis[t][to], dis[from][t] + dis[i][to]}); } anss = min(anss, ans);//對於每條免費邊答案取最小 } } cout << anss << "\n"; return 0; }