日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

AtCoder Regular Contest 061 E - Snuke‘s Subway Trip(建图 + dijkstra最短路 / 0/1bfs / 并查集)

發布時間:2023/12/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 AtCoder Regular Contest 061 E - Snuke‘s Subway Trip(建图 + dijkstra最短路 / 0/1bfs / 并查集) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

AtCoder Regular Contest 061 E - Snuke’s Subway Trip

problem

洛谷翻譯

my idea

最近一直在做網絡流,所以一讀這題后,我就想到了最小費用流。

首先的問題就是建邊問題。

不同線路到達同一個點從而引發后面的費用是相互獨立的,不能由同一個點表示。

所以我想到了拆點,把每條邊對應的兩個點都分別拆出一個虛點,此虛點就代表這條邊的顏色。

顯然每個點只會拆出與之關聯的邊不同顏色的個數,而一條邊只關聯兩個點,這最多是 O(n+2m)O(n+2m)O(n+2m) 的。

到目前為止都是可以接受的。

然后就是從一個站點到另一個站點之間的連邊,發現如果要把所有情況都包含,必須一個站點的所有拆點都向另一個站點的所有拆點連邊,費用為 1/01/01/0。別的不說,這邊數就是 O(m2)O(m^2)O(m2) 級別的了。

肯定的,我們非常想把每個站點的拆點都縮成一個虛點。

顏色不同的連虛點費用 111,顏色相同就不管。然而——stuck

solution

將邊當作點,正反向邊分別建點,建立源匯 s,ts,ts,t

先將原圖每個節點 uuu 按照出邊的顏色排序,保證相同顏色的出點 vvv 是連續的一段區間。

【以下在新圖中連邊參與的“點”都是指把邊當作點時,邊的編號】

  • 正反向邊之間連邊,費用 000

  • 如果邊起點為 111,連邊 (s,id,1)(s,id,1)(s,id,1)。因為從 sss 開始就相當于換了公司。

  • 如果 uuu 相同的兩條相鄰出邊 id1,id2id_1,id_2id1?,id2? 顏色一樣,那么相互連邊 (id1,id2,0),(id2,id1,0)(id_1,id_2,0),(id_2,id_1,0)(id1?,id2?,0),(id2?,id1?,0)

    因為這兩條邊可以免費走。這樣一段連續的相同顏色的邊兩兩之間都可以免費走了。

  • 考慮顏色轉化的點,暴力連邊如上面是會卡成平方的。

    新建一個虛點,對于 uuu 出邊的每種顏色,隨便取一條可以代表這種顏色的邊向虛點連邊 111

    【上一個連邊知道了相同顏色的邊是兩兩之間隨便走的,所以隨便選哪條連虛點都不影響。】

    虛點往這條隨便選取的邊連邊 000

    往虛點走就證明已經換了一家公司,然后虛點走向的點就是換完后代表的公司了。

    如果不走虛點就表示不換公司。

  • 如果邊終點為 nnn,連邊 (u,t,0)(u,t,0)(u,t,0)

每個點只會建立一個虛點,每條邊拆成正反兩條邊,還有源匯,總點數為 O(n+2m+2)O(n+2m+2)O(n+2m+2)

邊數也是差不多級別的。

費用只有 0/10/10/1 之分,而且這個費用可以看作是邊權。

0/1 bfs 可以做到線性,但是堆優化 dijkstra 跑個最短路,更板子不用腦一點直接寫。

code

#include <bits/stdc++.h> using namespace std; #define maxn 2000005 #define inf 0x7f7f7f7f #define Pair pair < int, int > struct node { int v, c, id; }; vector < node > E[maxn]; vector < Pair > G[maxn]; priority_queue < Pair, vector < Pair >, greater < Pair > > q; int n, m, s, t; int dis[maxn], tag[maxn];void dijkstra() {memset( dis, 0x7f, sizeof( dis ) );q.push( { dis[s] = 0, s } );while ( q.size() ) {int u = q.top().second, d = q.top().first; q.pop();if( dis[u] ^ d ) continue;for( int i = 0; i < G[u].size();i ++ ) {int v = G[u][i].first, w = G[u][i].second;if( dis[v] > dis[u] + w ) {dis[v] = dis[u] + w;q.push( { dis[v], v } );}} } }int main() {scanf( "%d %d", &n, &m );for( int i = 1, u, v, c;i <= m;i ++ ) {scanf( "%d %d %d", &u, &v, &c );E[u].push_back( { v, c, i << 1 } );E[v].push_back( { u, c, i << 1 | 1 } );}s = 1, t = m * 2 + 2; int tot = t;for( int i = 1;i <= n;i ++ ) {tot ++;sort( E[i].begin(), E[i].end(), []( node x, node y ) { return x.c < y.c; } );for( int j = 0;j < E[i].size();j ++ ) {int k = E[i][j].v, c = E[i][j].c, id = E[i][j].id;if( tag[c] ^ i ) {tag[c] = i;G[tot].push_back( { id, 0 } );G[id].push_back( { tot, 1 } );}G[id].push_back( { id ^ 1, 0 } );if( i == 1 ) G[s].push_back( { id, 1 } );if( k == n ) G[id].push_back( { t, 0 } );if( j and c == E[i][j - 1].c ) G[id].push_back( { E[i][j - 1].id, 0 } ), G[E[i][j - 1].id].push_back( { id, 0 } );}}dijkstra();printf( "%d\n", dis[t] == inf ? -1 : dis[t] );return 0; }

總結

以上是生活随笔為你收集整理的AtCoder Regular Contest 061 E - Snuke‘s Subway Trip(建图 + dijkstra最短路 / 0/1bfs / 并查集)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。