次短路-POJ3255

思路

這是嚴(yán)格次短路。(題目數(shù)據(jù)有點水暇唾。促脉。辰斋。。瘸味。)
到某個頂點v的次短路要么是其他某個頂點u的最短路再加上e(u,v)宫仗,要么是到u的次短路再加上e(u,v)的邊。因此對于每個頂點旁仿,我們記錄的不僅僅的最短距離藕夫,還有次短距離。
考慮在什么情況下會更新最短路枯冈。(可重復(fù)走同一條邊)
1毅贮、由父親節(jié)點過來的距離小于最短路,那么當(dāng)前最短路變成次短路尘奏,更新最短路
2滩褥、若當(dāng)前距離不能更新最短路,但比次短路小炫加,更新次短路
3瑰煎、若從父親節(jié)點過來的次短路能更新當(dāng)前次短路,更新次短路
所以俗孝,求次短路只需要在更新最短路的時候順便更新次短路就好了

模擬酒甸,可幫助理解上述黑體加粗

例題 POJ3255

送上一個案例
4 6
1 2 1
1 2 5
1 3 2
2 3 2
2 4 1
2 4 6

解法一:dij變形

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> iip;
typedef pair<ll, ll> llp;
const int MAXN = 100005;
const int MAXM = 100005;
const int INF = 0x3f3f3f3f;
const int MOD = 998244353;

int i, j, n, m, a, b, d, cnt, dis[MAXN], dis2[MAXN], head[MAXN];
struct edge{
    int u;
    int v;
    int w;
    int next;
    edge(){};
    edge(int _u, int _v, int _w, int _next) : u(_u), v(_v), w(_w), next(_next) {};
}e[2*MAXM];

void init() {
    cnt = 0;
    for(i = 0; i <= n; i++) {
        dis[i] = INF;
        dis2[i] = INF;
        head[i] = -1;
    }
}

void addEdge(int u, int v, int w) {
    e[cnt] = edge(u, v, w, head[u]);
    head[u] = cnt++;
}

void dij(int s) {
    dis[s] = 0;
    priority_queue<iip, vector<iip>, greater<iip> > pq;
    pq.push({dis[s], s});
    while(!pq.empty()) {
        iip now = pq.top();
        pq.pop();
        int u = now.second;
        int d = now.first;
        if(dis2[u] < d)  continue;
        for(i = head[u]; i != -1; i = e[i].next) {
            int d2 = d + e[i].w;//注意此處與最短路的區(qū)別,取出的當(dāng)前最小距離不一定是離起始點的最短距離驹针,還可以是次小距離烘挫!所以不能用 d2 = dis[u] + e[i].w;
            int v = e[i].v;
            if(dis[v] > d2) {//如果父親結(jié)點過來的距離小于最短路
                swap(dis[v], d2);//那么當(dāng)前最短路變成次短路,更新最短路
                pq.push({dis[v], v});
            }
            if(dis2[v] > d2 && dis[v] < d2) {//若當(dāng)前距離不能更新最短路柬甥,但比當(dāng)前次短路幸;或者從父親結(jié)點過來的次短路比當(dāng)前次短路小
                dis2[v] = d2;//更新次短路
                pq.push({dis2[v], v});
            }
        }
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    init();
    while(m--) {
        scanf("%d%d%d", &a, &b, &d);
        addEdge(a, b, d);
        addEdge(b, a, d);
    }
    dij(1);
    printf("%d\n", dis2[n]);
    return 0;
}

解法二:利用第k短路算法

這題數(shù)據(jù)還是很弱的苛蒲,以下第 k 短路算法并沒有遵守題意中的嚴(yán)格次短路還是AC了卤橄,讀者可自行測試數(shù)據(jù):
4 4
1 2 1
1 3 1
2 4 1
3 4 1
解法一:ans = 4;
解法二:ans = 2;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> llp;
typedef pair<int, int> iip;
const int MAXN = 200005;
const int MAXM = 200005;
const int INF = 0x3f3f3f3f;
const int MOD = 998244353;

int i, j, n, m, cnt, a, b, d, head[MAXN], dis[MAXN], num = 0;

struct edge{
    int u, v, w, next;
    edge(){};
    edge(int _u, int _v, int _w, int _next) : u(_u), v(_v), w(_w), next(_next) {};
}e[MAXM];

struct node{
    int g, v;//g(n)起點到頂點v的實際距離
    node(){};
    node(int _g, int _v) : g(_g), v(_v) {};
    bool operator < (const node &x) const{
        return g + dis[v] > x.g + dis[x.v];//f(n) = g(n) + h(n)
    }
};

void init() {
    cnt = 0;
    for(i = 0; i <= n; i++) {
        dis[i] = INF;
        head[i] = -1;
    }
}

void addEdge(int u, int v, int w) {
    e[cnt] = edge(u, v, w, head[u]);
    head[u] = cnt++;
}

void dij(int s) {
    priority_queue<iip, vector<iip>, greater<iip> > pq;
    dis[s] = 0;
    pq.push({dis[s], s});
    while(!pq.empty()) {
        iip now = pq.top();
        pq.pop();
        int u = now.second;
        if(dis[u] < now.first) continue;
        for(i = head[u]; i != -1; i = e[i].next) {
            int v = e[i].v;
            if(dis[u] != INF && dis[u] + e[i].w < dis[v]) {
                dis[v] = dis[u] + e[i].w;
                pq.push({dis[v], v});
            }
        }
    }

}

int Astar(int s, int t, int k) {
    if(dis[s] ==  INF)  return -1;//不存在第k短路
    priority_queue<node> pq;//根據(jù)估值函數(shù)搜索
    if(s == t)  k++;//起點和終點相同時,需繞一圈再回來
    pq.push(node(0, s));
    while(!pq.empty()) {
        node now = pq.top();
        pq.pop();
        if(now.v == t) num++;//若為嚴(yán)格第k短路臂外,可用set存每次到達終點的距離窟扑,根據(jù)set的大小來判斷是否到達嚴(yán)格第k短路
       if(num == k)    return now.g;//走到第k短路時,返回實際距離
        for(i = head[now.v]; i != -1; i = e[i].next) {
            pq.push(node(now.g + e[i].w, e[i].v));//g(n) = 父親結(jié)點的 g + 這條邊的距離
        }
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    init();
    while(m--) {
        scanf("%d%d%d", &a, &b, &d);
        addEdge(a, b, d);
        addEdge(b, a, d);
    }
    dij(n);//h(n)漏健,各個頂點到終點n的估計距離(最短距離)嚎货,有向圖需反向
    int ans = Astar(1, n, 2);
    printf("%d\n", ans);
    return 0;
}

參考文章1
參考文章2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蔫浆,隨后出現(xiàn)的幾起案子殖属,更是在濱河造成了極大的恐慌,老刑警劉巖瓦盛,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洗显,死亡現(xiàn)場離奇詭異外潜,居然都是意外死亡,警方通過查閱死者的電腦和手機挠唆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門处窥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人玄组,你說我怎么就攤上這事滔驾。” “怎么了巧勤?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵嵌灰,是天一觀的道長。 經(jīng)常有香客問我颅悉,道長,這世上最難降的妖魔是什么迁匠? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任剩瓶,我火速辦了婚禮,結(jié)果婚禮上城丧,老公的妹妹穿的比我還像新娘延曙。我一直安慰自己,他們只是感情好亡哄,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布枝缔。 她就那樣靜靜地躺著,像睡著了一般蚊惯。 火紅的嫁衣襯著肌膚如雪愿卸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天截型,我揣著相機與錄音趴荸,去河邊找鬼。 笑死宦焦,一個胖子當(dāng)著我的面吹牛发钝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播波闹,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼酝豪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了精堕?” 一聲冷哼從身側(cè)響起孵淘,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锄码,沒想到半個月后夺英,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晌涕,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了惧财。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖仰迁,靈堂內(nèi)的尸體忽然破棺而出徐许,到底是詐尸還是另有隱情雌隅,我是刑警寧澤恰起,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布和泌,位于F島的核電站武氓,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏东羹。R本人自食惡果不足惜忠烛,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一冤议、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧堪滨,春花似錦蕊温、人聲如沸义矛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽量蕊。三九已至,卻和暖如春缩滨,著一層夾襖步出監(jiān)牢的瞬間泉瞻,已是汗流浹背袖牙。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工司忱, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留畴蹭,地道東北人坦仍。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像叨襟,于是被迫代替她去往敵國和親繁扎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355