挂个链接:
zkw的zkw博客
原理参考zkw的博客
题目:
cf edu 109 D
两个版本:区别在最短路的求法上面
1.修改顶标(原始版本)
适用于:最终流量较大, 而费用取值范围不大的图, 或者是增广路径比较短的图 (如二分图),
#include<bits/stdc++.h>
#define For(aa, bb, cc) for(int aa = (bb); aa <= (int)(cc); ++aa)
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 5e3 + 10, maxm = 1e6 + 10;
int n, s, t, allflow, allcost;
int a[maxn];
int vis[maxn], cur[maxn], dis[maxn];
int be[maxn], ne[maxm], to[maxm], flow[maxm], cost[maxm], e;
void add_edge(int x, int y, int z, int w){
to[++e] = y, ne[e] = be[x], be[x] = e, flow[e] = z, cost[e] = w;
to[++e] = x, ne[e] = be[y], be[y] = e, flow[e] = 0, cost[e] = -w;
}
int dfs(int u, int f){
vis[u] = 1;
if(u == t) return allcost += dis[s] * f, allflow += f, f;
int sum = 0;
for(int &i = cur[u]; i; i = ne[i]){
int v = to[i];
if(!vis[v] && flow[i] > 0 && dis[v] == dis[u] - cost[i]){
int tmp = dfs(v, min(flow[i], f));
if(tmp){
flow[i] -= tmp;
flow[i ^ 1] += tmp;
f -= tmp;
sum += tmp;
}
if(!f) return sum;
}
}
return sum;
}
bool spfa(){
For(i, 1, n + 2) dis[i] = inf, vis[i] = 0;
deque<int> q;
dis[t] = 0;
q.push_back(t);
while(!q.empty()){
int u = q.front();
q.pop_front();
vis[u] = 0;
for(int i = be[u]; i; i = ne[i]){
int v = to[i];
if(flow[i ^ 1] > 0 && dis[v] > dis[u] - cost[i]){
dis[v] = dis[u] - cost[i];
if(!vis[v]){
vis[v] = 1;
if(!q.empty() && dis[v] < dis[q.front()]) q.push_front(v);
else q.push_back(v);
}
}
}
}
return dis[s] < inf;
}
void minflow(){
allflow = allcost = 0;
while(spfa()){
memset(vis, 0, sizeof vis);
memcpy(cur, be, sizeof be);
dfs(s, inf);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(NULL);
cin >> n;
For(i, 1, n) cin >> a[i];
e = 1;
s = n + 1, t = n + 2;
For(i, 1, n){
if(a[i]) add_edge(s, i, 1, 0);
else add_edge(i, t, 1, 0);
}
For(i, 1, n - 1) add_edge(i, i + 1, inf, 1), add_edge(i + 1, i, inf, 1);
minflow();
printf("%d\n", allcost);
return 0;
}
2.spfa的SLF优化(比较普适)
#include<bits/stdc++.h>
#define For(aa, bb, cc) for(int aa = (bb); aa <= (int)(cc); ++aa)
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 5e3 + 10, maxm = 1e6 + 10;
int n, s, t, allflow, allcost;
int a[maxn];
int vis[maxn], cur[maxn], dis[maxn];
int be[maxn], ne[maxm], to[maxm], flow[maxm], cost[maxm], e;
void add_edge(int x, int y, int z, int w){
to[++e] = y, ne[e] = be[x], be[x] = e, flow[e] = z, cost[e] = w;
to[++e] = x, ne[e] = be[y], be[y] = e, flow[e] = 0, cost[e] = -w;
}
int dfs(int u, int f){
vis[u] = 1;
if(u == t) return allcost += dis[s] * f, allflow += f, f;
int sum = 0;
for(int &i = cur[u]; i; i = ne[i]){
int v = to[i];
if(!vis[v] && flow[i] > 0 && dis[v] == dis[u] - cost[i]){
int tmp = dfs(v, min(flow[i], f));
if(tmp){
flow[i] -= tmp;
flow[i ^ 1] += tmp;
f -= tmp;
sum += tmp;
}
if(!f) return sum;
}
}
return sum;
}
bool spfa(){
For(i, 1, n + 2) dis[i] = inf, vis[i] = 0;
deque<int> q;
dis[t] = 0;
q.push_back(t);
while(!q.empty()){
int u = q.front();
q.pop_front();
vis[u] = 0;
for(int i = be[u]; i; i = ne[i]){
int v = to[i];
if(flow[i ^ 1] > 0 && dis[v] > dis[u] - cost[i]){
dis[v] = dis[u] - cost[i];
if(!vis[v]){
vis[v] = 1;
if(!q.empty() && dis[v] < dis[q.front()]) q.push_front(v);
else q.push_back(v);
}
}
}
}
return dis[s] < inf;
}
void minflow(){
allflow = allcost = 0;
while(spfa()){
memset(vis, 0, sizeof vis);
memcpy(cur, be, sizeof be);
dfs(s, inf);
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(NULL);
cin >> n;
For(i, 1, n) cin >> a[i];
e = 1;
s = n + 1, t = n + 2;
For(i, 1, n){
if(a[i]) add_edge(s, i, 1, 0);
else add_edge(i, t, 1, 0);
}
For(i, 1, n - 1) add_edge(i, i + 1, inf, 1), add_edge(i + 1, i, inf, 1);
minflow();
printf("%d\n", allcost);
return 0;
}