1. 程式人生 > >[JZOJ2702] 【GDKOI2012模擬02.01】探險

[JZOJ2702] 【GDKOI2012模擬02.01】探險

題目

在這裡插入圖片描述

題目大意

給你一個每條邊正反權值不一定相同的無向圖,求起點為 1 1 點的最小環。


思考歷程

一看到這題,就覺得是一個經典模型。
然後思考先前做過最小環的經歷,發現沒個卵用。
我突然想到,既然這一個環是在 1 1

點上的,那麼肯定有兩條邊和 1 1 相連。
一個很顯然的思路就是,列舉與 1 1 相連的邊,然後計算帶著這條邊最小環。
首先處理一個最短路,並且在帶一個前驅,表示從哪一個邊轉移過來。
列舉和 1
1
相連的每一條邊,設另一個點為 x x ,如果 x x 的前驅不是 1
1
,那麼直接為 d i s ( x ) + l e n ( x , 1 ) dis(x)+len(x,1)
問題來了,前驅是 1 1 怎麼辦?
有一個很暴力的思路,就是將這條邊刪掉,再跑一遍最短路徑。
時間肯定會炸啊!(後來:呵呵)
其實我們只需要保證再求一個最短路,使得這個最短路的前驅不是 1 1 ,那就可以搞定了。
我們還是要保證這個儘量短,所以這是一個次短路。
現在的瓶頸就是,如何求次短路呢?
於是我懵逼了,求次短路萬一不能保證時間複雜度怎麼辦?
最後想不到什麼穩妥的解法,於是暴力一點,就將邊刪去,然後跑最短路。
結果……100分?
出題人啊,想想你的資料,讓一個 O ( m 2 ) O(m^2) 的蒟蒻都過了。


水法

特意新增這個欄目……
其實我的這個做法算是水法吧,只不過這明明是60分的方法啊……
SLS大佬,用暴力跑過了這題!
怎麼暴力?用IDA*!
二分一下環的長度,然後遞迴來幹!
設一個估價函式,就是它到 1 1 的最短路徑。
然後加了各種剪枝……
比如說,如果在遞迴的過程當中出現了環,就退出……
反正是一堆優化。
然後輕易地水過這題。


正解

先說一說第一個正解。
其實我想得已經非常接近了,就是求最短路和次短路啊!
怎麼求次短路呢?題解中解釋得有些籠統,就是說用SPFA不停迭代直到穩定為止。
原來,事情並沒有我想象中的那麼複雜……
就是在轉移的時候多了一個次短路的轉移而已……其實也不用特意在意它是次短的,只需要第一條邊和最短路不一樣就行了。
然後我有一個問題,如果有點 x x ,它轉移到 y y ,不如 y y 的次短路,所以會被踢掉;可是如果它繼續從 y y 轉移到 z z ,那又能更新 z z 的次短路。有沒有這種情況呢?
如果有這種情況,那就是 y y 原來的次短路和 z z 的最短路的初始邊相同,但 x x 的次短路和 z z 的最短路的初始邊不同,所以就有可能轉移過去。
某大爺解釋道:如果 y y 原來的次短路和 z z 的最短路的初始邊相同,那麼 y y 的最短路和 z z 的最短路的初始邊一定不同,那這也是可以轉移過去的。
所以說,直接求在正確性上似乎沒有什麼問題。
然後時間呢?
時間我就不清楚了,有點玄學。

然後就是一個比較正經的解法,時間複雜度絕對優秀(可以用Dijkstra):
這個方法就是構造一個新圖,在裡面跑最短路。
首先我們將每一個點的最短路給算出來,並且記錄它們最短路經過的邊(記住是邊!題解害死人!不過我沒有受騙),記作 f i r fir
設新圖中源點為 S S .,匯點為 T T 。(不要想到網路流去了!)
對於從 1 1 連出去的邊 e ( 1 , x , l e n ) e(1,x,len)
如果 f i r ( x ) = e fir(x)=e ,不要理它。
否則,就在新圖中連 ( S , x , l e n ) (S,x,len)
對於從 x x 連回 1 1 的邊 e ( x , 1 , l e n ) e(x,1,len)
如果 f i r ( x ) = e fir(x)=e ,連 ( x , T , l e n ) (x,T,len)
否則,連 ( S , T , d i s ( x ) + l e n ) (S,T,dis(x)+len)
對於其它的邊 ( u , v , l e n ) (u,v,len)
如果 f i r ( u ) = f i r ( v ) fir(u)=fir(v) ,就連 ( u , v , l e n ) (u,v,len)
否則連 ( S , u , d i s ( u ) + l e n ) (S,u,dis(u)+len)
然後整個圖就建完了,從 S S 點跑一遍到 T T 的最短路就好了。
這個方法真的是十分巧妙,具體是為什麼呢?
我斟酌了很久……
我們試著分個類:
對於和 1 1 相連的邊 e ( x , 1 ) e(x,1) ,如果 x x 的最短路徑是從 1 1 開始,走其它的邊到了 x x ,那麼答案顯然是 d i s ( x ) + l e n dis(x)+len ,對應上面的 ( S , T , d i s ( x ) + l e n ) (S,T,dis(x)+len) 。那麼 x x 不會直接連到 T T ,所以不會有從 S S 出來,走向同道路回去的尷尬情況。
如果 x x 的最短路徑是從 1 1 直接走這條邊到 x x 的,通過上面我們建的圖,我們可以發現,它在 S S 這邊沒有,在 T T 這邊有,所以不可能走同一條邊。
現在有一個問題,可能出現這樣的情況:最小環和 1 1 相連的兩個點, 1 1 到它們的最短路徑都是直接從 1 1 走到它們,那樣有沒有可能算漏呢?
我們再看看邊 e ( u , v ) e(u,v) 其中 u u v v 都不是 1 1
如果 f i r ( u ) = f i r ( v ) fir(u)=fir(v) ,那麼它們的最短路是從同一條邊走過來的,不能直接組成環,所以按照原樣。
否則,它們是可以形成一個環的。設 x x 為邊 f i r ( u ) fir(u) 的除 1 1 外的那一端的點,顯然 x x 的最短路是直接從 1 1 走過來的,可是現在這條路沒了啊!(上面沒有建出來)
不怕,直接連 ( S , v , d i s ( u ) + l e n ) (S,v,dis(u)+len) ,直接連過去。
我們再回顧一下上面有沒有可能算漏的問題,雖然說兩個點和 1 1 相連的邊不能直接連通,但是它們是可以用這種方式連通的啊!所以它們是可以被計算到的。
這樣建圖既可以保證所有合法的環都可以走,又可以扼殺從同一條邊走回去的機會。
時間複雜度是很穩定的,畢竟只是求兩遍最短路罷了,如果你打Dijkstra,那就不會被卡。由於我比較懶惰,所以還是打了SPFA。


程式碼

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 10000
#define M 200000
int n,m;
struct EDGE{
	int to,len,num;
	EDGE *las;
} e[M*4+1];
int ne;
EDGE *last1[N+2],*last2[N+2];
inline void link(EDGE *last
            
           

相關推薦

[JZOJ2702] GDKOI2012模擬02.01探險

題目 題目大意 給你一個每條邊正反權值不一定相同的無向圖,求起點為 1 1 1點的最小環。

GDKOI2012模擬02.01數字

想了2個小時。。。都想到數位DP去了,雖然沒打(但是我瘋了) 打表找規律。比賽時打了個表發現每九個的D()都是一迴圈(1~9) 然後想著怎麼做,先打了個暴力然後在想,沒想到的是: 如果x為喜歡的數的話,那麼x+22680也是喜歡的數。 為什麼? 設x=a·D(a),那麼x+22680

[JZOJ2701] GDKOI2012模擬02.01矩陣

題目 題目大意 給你一個矩陣,然後你需要構造一個等長等寬的矩陣,其中矩陣的每一個數字都有一個固定的範圍 [ L

[JZOJ2700] GDKOI2012模擬02.01數字

題目 題目大意 其實這題的題目大意非常簡練,所以我認為我不用解釋了。 思考歷程 首先亂推了一波,然後什麼東西都沒有發現。 於是想想 D

JZOJ5944. NOIP2018模擬11.01信標

題意: 資料範圍: 對於前 20 20 20% 的資料,

JZOJ-senior-5943. NOIP2018模擬11.01

Time Limits: 1000 ms Memory Limits: 262144 KB Description Input 第一行一個整數 n 表示序列長度, 接下來一行 n 個整數描述這個序列. 第三行一個整數 q 表示操作次數, 接下來 q 行每行一次操作, 格

JZOJ-senior-5941. NOIP2018模擬11.01

Time Limits: 2000 ms Memory Limits: 262144 KB Description Input Output Sample Input Sample Input1: 4 3 9 6 5 8 7 7 Sample I

jzoj5943. NOIP2018模擬11.01樹(線段樹)

5943. 【NOIP2018模擬11.01】樹 Description Input 第一行一個整數 n 表示序列長度, 接下來一行 n 個整數描述這個序列. 第三行一個整數 q 表示操作次數, 接下來 q 行每行一次操作, 格式同題目描述. Output 輸

NOIP2018模擬11.01

題目 描述 題目大意 維護一個序列,支援三種操作: 1、修改一段區間,將這段區間內的所有數都andandand一個數。 2、詢問區間和。 3、詢問區間兩兩相加的平方和。 N≤10000N\leq 10000N≤10000 思路 顯然是一道資料結構題。 毋

JZOJ 5943. NOIP2018模擬11.01

題目 對於 100% 的資料,n,q≤105n, q ≤ 10^5n,q≤105,ai≤109,ai ≤ 10^9,ai≤109,$ k ≤ 2^30,1≤l≤r≤n., 1 ≤ l ≤ r ≤ n.,1≤l≤r≤n. 題解 每個數多被減30次。 線段樹維護,

JZOJ5944.NOIP2018模擬11.01信標

PROBLEM 建立最少的信標,使得任意兩個點到至少一個信標的距離不同 SOLUTION 當n>1時,信標的個數>0,於是我們可以列舉其中一個信標的位置,將這個樹的根就定為這個點,那麼點就分層互不影響。 考慮當我們在根上放信標後,我們在一個點上放信標,對於它的子樹

ROS機器人作業系統初探索02.01MoveIt!

安裝的部分我就省略了,跟著官網的步驟來就可以了(需要詳細翻譯步驟的話,可以留言,需要的人多的話,我就出個翻譯教程),第二部分學習完之後先不要跳到MoveIt!Setup Assistant tutorial,先按照它側目錄的步驟走,不然可能有一些需要tutorial裡面需要用

jzoj5141 NOI2017模擬6.12說無可說

題目 display nbsp stdout hid sed targe view n) 傳送門:https://jzoj.net/senior/#main/show/5141 【題目大意】 給出n個字符串,求有多少組字符串之間編輯距離為1~8。 n<=200,∑|S

NOIP2017模擬8.5隊伍統計

優先級 con isp pla cnblogs noip 技術分享 freopen 100% Description 現在有n個人要排成一列,編號為1->n 。但由於一些不明原因的關系,人與人之間可能存在一些矛盾關系,具體有m條矛盾關系(u,v),表示編號

NOI2015模擬8.14A+B

std out 一個 blog sam 數據 -a spl stream Description 對於每個數字x,我們總可以把它表示成一些斐波拉切數字之和,比如8 = 5 + 3, 而22 = 21 + 1,因此我們可以寫成 x = a1 * Fib1 + a2

NOIP2017模擬8.8Trip

關系 pan 根據 大於 二叉 計算 我們 else freopen Description 多年之後,worldwideD厭倦競爭,隱居山林。 他的家鄉開始發展起了旅遊業,在一條很長的主幹道上,有N個旅遊景點,按順序編號為1到N。根據遊客們

[jzoj]2938.NOIP2012模擬8.9分割田地

script 連通 分配 mathjax cnblogs 沒有想到 -1 str 需要 Link   https://jzoj.net/senior/#main/show/2938 Description   地主某君有一塊由2×n個柵格組成的土地,有k個

NOIP模擬10-21的士碰撞

min urn cmp dir cnblogs struct noip 開始 format Description ??輛車在一條數軸上,車的編號為1到??。編號為??的車坐標為??[??],初始方 向為??????[??](左或右),初始位置兩兩不同。每輛車每個時刻行

bzoj4551NOIP2016模擬7.11

for noip 給定 getc detail 問題 實現 href 並查集 題目 在2016年,佳媛姐姐剛剛學習了樹,非常開心。現在他想解決這樣一個問題:給定一顆有根樹(根為1),有以下 兩種操作:1. 標記操作:對某個結點打上標記(在最開始,只有結點1有標記,其他結點均

bzoj 4554Tjoi2016&Heoi2016NOIP2016模擬7.12遊戲

Go AI %d amp noip 現在 匹配 .net space 題目 分析 當沒有石頭的時候,就用二分圖匹配來做。 但現在加入了石頭, 所以,求出每行和每列聯通快的個數,如果有一塊平地,包括在某個行聯通塊以及某個列聯通塊中,連邊。 //無聊打了網絡流,匈牙利也可以