2019美賽d題演算法之二,啟發自我的acm隊友zht
傳統圖論網路的最大流問題需要計算出某個單源單匯網路中從源點到匯點的最大流量,即單位時間內最多流過多少量,已有許多成熟的演算法如dinic演算法。
而在多源多匯擴散模型中,源點處的量(人數)有限,目標變為使得時間最小,有多個源點,多個匯點。為此我們提出了按時間分層最大流演算法。
n個點,m條邊;
n個點中有若干個匯點(出口);
不為匯點的點中有若干個源點,每個源點都有初始人數;
每條邊都有通過它所需的最大流量和通過時間。
目標:使用最少的時間將所有處於源點的人排程到匯點,給出排程方案。
考慮到存在時間的影響,每一秒鐘每個節點處的人數都可能與上一秒鐘不同,我們引入了按時間分層的概念。建立乙個分層網路,每一層都有n個節點。初始時(第0秒)所有人都在第0層,在第t秒時所有人從t-1層到達第t層。這樣,f層的分層網路從源點到匯點的最大流量就是原系統在f秒內能夠疏散的最多人數。隨著層數的增加系統的最大流量會逐漸增加直到等於原系統所有源點的初始人數。注意到當前層數小於目標時間時,網路的最大流始終小於初始人數;而當前層數大於目標時間時,網路的最大流始終等於初始人數。所以我們可以使用二分搜尋的方法去尋找最優時間。
原系統路徑圖:
分層圖:
dinic演算法的時間複雜度為o(n
2∗m)
o(n^2*m)
o(n2∗m
),tt
t層的分層網路中一共有o(n
∗t)o(n*t)
o(n∗t)
個點,o((n+m)*t)條弧。所以每次建立分層網路並求解最大流的時間複雜度為o(n
2(n+
m)t3
)o(n^2(n+m)t^3)
o(n2(n
+m)t
3)。使用二分法尋找時,一共需要建立o
(logt
)o(\log t)
o(logt
)次網路。所以本演算法的總時間複雜度為o(n
2(n+
m)t3
logt)
o(n^2(n+m)t^3\log t)
o(n2(n
+m)t
3logt)
。實際上由於dinic演算法的平均表現遠優於它的複雜度上界,我們的演算法也可以在預期的時間內得到羅浮宮疏散模型的計算結果。
使用二分法選擇層數f,按2-5步建立分層網路;
分層:分層網路中一共有f+1
f+1f+
1層,編號從0
00到fff;
新增節點:網路一共有(f+
1)∗n
+2(f+1)*n+2
(f+1)∗
n+2個節點,
其中f+
1f+1
f+1層每層有n
nn個節點,第i
ii層第j
jj個結點的編號是i∗n
+ji*n+j
i∗n+
j此外有1個超級源點編號為000;
有1個超級匯點編號為(f+
1)∗n
+1(f+1)*n+1
(f+1)∗
n+1;
新增弧:
超級源點到第0層的所有源點都有一條弧,容量為這個點的初始人數;
每一層的所有節點到它後一層的對應點之間有一條弧,容量無限;
如果原圖中有一條從u
uu指向v
vv、容量為cap
capca
p、耗時為tim
etime
time
的邊,那麼對於所有的0
<=i
<=f
−tim
e0<=i<=f-time
0<=i
<=f
−tim
e,第i
ii層的第u
uu個點應向i+t
imei+time
i+time
層的第v
vv個點連一條容量為cap
capca
p的弧;
第f
ff層的所有匯點向超級匯點連一條弧,容量無限;
對分層網路執行dinic最大流演算法,得到每一條弧的流量及網路的最大流量;
二分法執行完畢後,得到疏散完畢的最小時間t
tt以及此時t層的分層網路流量情況。且原系統每個節點每個時刻的流量分布都在分層網路中有對應,可以用來進行非常細緻的安排。
**已修改,修改後的**和輸入資料見
#include
using
namespace std;
const
int m =
10016
, inf =
1000000007
;struct dinic
;int n, m, s, t;
vector edges;
vector<
int> g[m]
;bool vis[m]
;int d[m]
;int cur[m]
;void
addedge
(int from,
int to,
int cap)))
; edges.
push_back
(edge()
);m = edges.
size()
; g[from]
.push_back
(m -2)
; g[to]
.push_back
(m -1)
;}bool
bfs()}
}return vis[t];}
intdfs
(int u,
int a)
}return flow;
}int
maxflow
(int s,
int t)
return flow;}}
;struct problem
problem
(const string &filename)
maxflow =0;
for(
int i=
1;i<=n;
++i)
for(
int i=
0;i++i)
fin >> from[i]
>> to[i]
>> cap[i]
>> time[i];}
void
output()
//printf(" ");
}printf
("\n");
}}};
intmain
(void
)//printf("evacuation time cost: %ds.\n", ans );
pro.
output()
;}
多源匯最大流 關鍵邊
很簡單,建乙個超級源點連線所有的源點,建乙個超級匯點連線所有的匯點。author zhl date 2020 10 20 11 09 59 include define rep i,a,b for int i a i b i define repe i,u for int i head u i i ...
poj1459多源多匯最大流問題
基本構圖題,多源多匯,新增乙個源點和乙個匯點,所有源點都來自這個源點,同理,所有匯點 都匯於這個匯點,dinic第二戰,本來應該1a的,犯了乙個低階錯誤!while scanf d 要加 啊!sb了,記住這個教訓!此次順帶學習了scanf的又一讀入,忽略空格和已有符號,不錯,並且更加了解了 dini...
poj1459多源多匯最大流問題
基本構圖題,多源多匯,新增乙個源點和乙個匯點,所有源點都來自這個源點,同理,所有匯點 都匯於這個匯點,dinic第二戰,本來應該1a的,犯了乙個低階錯誤!while scanf d 要加 啊!sb了,記住這個教訓!此次順帶學習了scanf的又一讀入,忽略空格和已有符號,不錯,並且更加了解了 dini...