题意:
给定一个无向图,求从1到n的所有最短路径构成的网络图中的最小割。
思路:
其实就是dinic方法的小小变形,因为在我们求的时候需要处理一个层次图,又因为本题求最短路径的所有边都是单位边,正好符合dinic中的层次图,所以只需要在dis[T]不等于最初的层次时,我们就退出增广,从而求的就是最短路径构成的网络图中的最小割了。
但由于网上大多数都是先预处理一个所有可能的最短路径的DAG,再在这个有向图基础上求最小割,为什么是处理出一个有向图呢,如果是无向图,那么新图就有可能不按照我们题目中要求的所谓的最短路去走而造成了更大的流导致错误(网络流不会受无向边影响而造成特殊错误的,别瞎想= =),所以下面也贴一份代码。
代码1:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <cstdio>
#include <queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1005;
const int maxm = 4e4+5;
struct node
{
int v, w, next;
}edge[maxm];
int dis[maxn], pre[maxn], rec[maxn], head[maxn], block[maxn];
int n, m, no = 0;
int key;
queue<int> q;
inline void init()
{
no = 0;
memset(head, -1, sizeof head);
}
inline void add(int u, int v, int w)
{
edge[no].v = v; edge[no].w = w;
edge[no].next = head[u]; head[u] = no++;
edge[no].v = u; edge[no].w = 0;
edge[no].next = head[v]; head[v] = no++;
}
void reset(int S, int T)
{
memset(dis, 0x3f, sizeof dis);
memset(block, 0, sizeof block);
q.push(S); dis[S] = 0;
while(!q.empty())
{
int top = q.front(); q.pop();
for(int k = head[top]; k != -1; k = edge[k].next)
if(dis[edge[k].v] == inf && edge[k].w)
dis[edge[k].v] = dis[top]+1, q.push(edge[k].v);
}
}
int dinic(int S, int T)
{
int ans = 0, flow = inf, top = S;
pre[S] = S;
reset(S, T);
key = dis[T];
while(dis[T] != inf && dis[T] == key)
{
int k, tmp;
for(k = head[top]; k != -1; k = edge[k].next)
{
if(edge[k].w && dis[edge[k].v]==dis[top]+1 &&
!block[edge[k].v]) break;
}
if(k != -1)
{
tmp = edge[k].v;
flow = min(flow, edge[k].w);
pre[tmp] = top, rec[tmp] = k;
top = tmp;
if(top == T)
{
ans += flow; tmp = -1;
for(; top != S; top = pre[top])
{
edge[rec[top]].w -= flow;
edge[rec[top]^1].w += flow;
if(!edge[rec[top]].w) tmp = top;
}
flow = inf;
if(tmp != -1)
{
top = pre[tmp];
for(; top != S; top = pre[top])
flow = min(flow, edge[rec[top]].w);
top = pre[tmp];
}
}
}
else
{
block[top] = 1;
top = pre[top];
if(block[S]) reset(S, T);
}
}
return ans;
}
int main()
{
int t, u, v, w;
for(scanf("%d", &t); t--;)
{
scanf("%d %d", &n, &m);
init();
for(int i = 1; i <= m; ++i)
{
scanf("%d %d %d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
printf("%d\n", dinic(1, n));
}
return 0;
}
代码2:
#include <unordered_set>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <cstdio>
#include <queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1005;
const int maxm = 40005;
struct node{int v, w, next;} edge[maxm];
int dis[maxn], pre[maxn], rec[maxn], head[maxn], gap[maxn], now[maxn];
int t, n, m, no, up;
queue<int> q;
struct node1
{
int v, w, next;
bool operator<(const node1 k)const
{
return w > k.w;
}
} edge1[maxm];
int no1, head1[maxn];
int vis1[maxn], dis1[maxn];
unordered_set<int> G[maxn];
priority_queue<node1> q1;
queue<int> Q;
void init1()
{
no1 = 0;
memset(head1, -1, sizeof head1);
}
inline void add1(int u, int v, int w)
{
edge1[no1].v = v; edge1[no1].w = w;
edge1[no1].next = head1[u]; head1[u] = no1++;
}
inline void add(int u, int v, int w)
{
edge[no].v = v; edge[no].w = w;
edge[no].next = head[u]; head[u] = no++;
edge[no].v = u; edge[no].w = 0;
edge[no].next = head[v]; head[v] = no++;
}
inline void pre_init()
{
no = 0;
memset(head, -1, sizeof head);
}
void init(int S, int T)
{
memset(gap, 0, sizeof gap);
memset(dis, 0x3f, sizeof dis);
for(int i = 0; i <= n; ++i)
now[i] = head[i];
while(!q.empty()) q.pop();
dis[T] = 0; q.push(T);
while(!q.empty())
{
int tp = q.front(); q.pop();
++gap[dis[tp]];
int k = head[tp];
while(k != -1)
{
if(dis[edge[k].v] == inf && edge[k^1].w)
{
dis[edge[k].v] = dis[tp]+1;
q.push(edge[k].v);
}
k = edge[k].next;
}
}
}
int SAP(int S, int T)
{
up = n;
int ans = 0, flow = inf, top = S;
pre[S] = S; init(S, T);
while(dis[S] < up)
{
if(top == T)
{
ans += flow;
while(top != S)
{
edge[rec[top]].w -= flow;
edge[rec[top]^1].w += flow;
top = pre[top];
}
flow = inf;
}
int k = now[top];
while(k != -1)
{
int v = edge[k].v;
if(edge[k].w && dis[top] == dis[v]+1)
{
flow = min(flow, edge[k].w);
pre[v] = top; rec[v] = k;
now[top] = k; top = v;
break;
}
k = edge[k].next;
}
if(k == -1)
{
int mind = up;
if(--gap[dis[top]] == 0) break;
int k = now[top] = head[top];
while(k != -1)
{
if(edge[k].w && mind>dis[edge[k].v]) mind = dis[edge[k].v];
k = edge[k].next;
}
++gap[dis[top] = mind+1];
top = pre[top];
}
}
return ans;
}
void DJ()
{
while(!q1.empty()) q1.pop();
memset(vis1, 0, sizeof vis1);
memset(dis1, 0x3f, sizeof dis1);
q1.push((node1){1, 0, -1});
dis1[1] = 0;
while(!q1.empty())
{
node1 tp = q1.top(); q1.pop();
int u = tp.v;
if(vis1[u]) continue;
vis1[u] = 1;
for(int k = head1[u]; k+1; k = edge1[k].next)
{
int v = edge1[k].v;
if(dis1[v] > dis1[u]+1)
{
dis1[v] = dis1[u]+1;
G[v].clear();
G[v].insert(u);
q1.push((node1){v, dis1[v], -1});
}
else if(dis1[v] == dis1[u]+1) G[v].insert(u);
}
}
}
void work()
{
DJ();
while(!Q.empty()) Q.pop();
memset(vis1, 0, sizeof vis1);
Q.push(1); vis1[1] = 1;
while(!Q.empty())
{
int u = Q.front(); Q.pop();
for(int k = head1[u]; k+1; k = edge1[k].next)
{
int v = edge1[k].v;
if(G[v].find(u) != G[v].end())
{
add(u, v, edge1[k].w);
if(!vis1[edge1[k].v])
vis1[v] = 1, Q.push(v);
}
}
}
printf("%d\n", SAP(1, n));
}
int main()
{
for(scanf("%d", &t); t--;)
{
scanf("%d %d", &n, &m);
init1(); pre_init();
for(int i = 1; i <= m; ++i)
{
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
add1(u, v, w); add1(v, u, w);
}
work();
}
return 0;
}
继续加油~