/**
貼下最小費的鄰接表模板
圖算法中鄰接表應用極其廣泛,在速度和邊處理方面都要比矩陣好很多
最小費鄰接矩陣模板前面提到了 就不多說了
包括添邊等常用的技巧前面也都提到了
就是求網絡流是會用到逆流邊
用鄰接表添邊,逆流邊也相當經典,這個技巧剛開始並不好理解
比如:設edge[p] = ab; 則逆流邊爲 edge[p^1] = ba;
p^1 這是個什麼東西?? ^ 這個符號是異或,p^1 = ???
如果p 爲偶數則 p^1 = p+1, 如果p 爲奇數 p^1 = p-1;
所以p^1 總能得到一個與自己相鄰的數
把這個現象用到解決逆流邊上面,因爲添邊時候的下一條邊就爲逆流邊
所以如果從一個偶數開始
比如:從2開始 edge[2] = ab; edge[3] = ba; edge[4] = bc; edge[5] = cb;
每次都會添兩條邊,所以下一條邊開始必爲偶數 p ,而它的逆流邊即爲 p^1
具體看代碼
*/
struct {
int v, cap, cost, next;
}edge[eM]; //邊結構體 eM爲 最多有多少條邊
int ne, edgeHead[nM]; //nM爲 點的個數
int pre[nM]; //用來記錄增廣路徑
int ans, ne;
void addEdge(int u, int v, int c, int w) {
edge[ne].v = v;
edge[ne].cap = c;
edge[ne].cost = w;
edge[ne].next = edgeHead[u];
edgeHead[u] = ne++;
edge[ne].v = u;
edge[ne].cap = 0;
edge[ne].cost = -w;
edge[ne].next = edgeHead[v];
edgeHead[v] = ne++;
}
bool spfa(int s, int t) {
//spfa算法前面也介紹過,這裏用的棧模式,還有一個隊列版,簡單修改下就能得到
//一定要記住有時棧會超時,有時隊列也會超時,總有一個能過
int dis[nM], stack[nM], vis[nM];
int i, top = 0;
for (i=0; i<=n; i++) {
dis[i] = inf;
vis[i] = false;
}
dis[s] = 0;
stack[++top] = s;
vis[s] = true;
while (top) {
int u = stack[top--];
for (i=edgeHead[u]; i!=0; i=edge[i].next) {
int v = edge[i].v;
if (edge[i].cap && dis[v] > dis[u] + edge[i].cost) {
dis[v] = dis[u] + edge[i].cost;
pre[v] = i; //記錄路徑用的是邊號,所以 u = edge[p^1].v;
if (!vis[v]) {
vis[v] = true;
stack[++top] = v;
}
}
}
vis[u] = false;
}
if (dis[t] < inf) return true;
return false;
}
void end(int s, int t) {
//這些原理和鄰接矩陣一模一樣
int u, p, sum = inf;
for (u=t; u!=s; u=edge[p^1].v) {
p = pre[u];
sum = min(sum, edge[p].cap);
}
for (u=t; u!=s; u=edge[p^1].v) {
//嗯,這個好好模擬下,技巧噢
p = pre[u];
edge[p].cap -= sum;
edge[p^1].cap += sum;
ans += edge[p].cost * sum;
}
}
int main() {
//初始化
memset(edgeHead, 0, sizeof (edgeHead));
ne = 2; //一定要從偶數開始,因爲edgeHead 初始化爲0 了所以賦值爲2
ans = 0; //最小費
/**
***建圖添邊****
調用addEdge()添邊,uv 表示一條邊,c爲流量,w爲花費
則 addEdge(u, v, c, w); 即可
這纔是重重之中的技能
關鍵在建圖,模板都會套
*/
//調用
while (spfa(s, t))
end(s, t);
//s爲源點,t爲匯點
return 0;
}
收藏於 2012-01-12
最小費spfa()+ek() 鄰接表
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.