图论 网络流
最大流 INF(初始值)
路径上权值最小的边,决定流量大小。
流量网络的三个特性:
①流量控制
②反对称性
③流量守恒
残余网络:保留了c(e)容量<f(e)流量【可以继续流,因为还有f(e)-c(e)的流量】和 c(e)>0的反向边【可以回退】。
增广路定理:网络中达到最大流当且仅当残余网络中不存在增广路。
所以总结做题方法就是不断找增广路,有三种方法:
①Ford-Fvkerson(DFS)
伪代码:
不断地在残余网络中找增广路伪代码:
FF{
flow=0;
while(true)
{
}
DFS遍历传参伪代码过程:
dfs(int now,int t,int cnt)
{
if(now==t) return cnt;
for(i)
if(!vis[i] && cap>0)
vis[i]=true;
d=dfs(next,t,min(cnt,cap)
if(d>0)
else
return 0;
}
两个技巧:
①邻接表
②邻接矩阵 [i][j]=cap [j][i]=0;
F - Flow Problem
For each test case, the first line contains two integers N and M,
denoting the number of vertexes and edges in the graph. (2 <= N <=
15, 0 <= M <= 1000)
Next M lines, each line contains three integers X, Y and C, there is
an edge from X to Y and the capacity of it is C. (1 <= X, Y <= N,
1 <= C <= 1000)OutputFor each test cases, you should output the maximum flow from source 1 to sink N.Sample Input
2
3 2
1 2 1
2 3 1
3 3
1 2 1
2 3 1
1 3 1
Sample Output
Case 1: 1
Case 2: 2
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
queue <int> q;
int n,m,gra[][],path[],flow[],st,ed;
int bfs()
{
int i,t;
while(!q.empty()) q.pop();
memset(path,-,sizeof(path));
path[st]=;
flow[st]=;
q.push(st);
while(!q.empty())
{
t=q.front();
q.pop();
if(t==ed) break;
for(i=;i<=n;i++)
{
if(i!=st && path[i]==- && gra[t][i])
{
flow[i]=flow[t]<gra[t][i]?flow[t]:gra[t][i];
q.push(i);
path[i]=t;
}
}
}
if(path[ed]==-) return -;
return flow[n];
} int ek()
{
int max_flow=,step,now,pre;
while((step=bfs())!=-)
{
max_flow+=step;
now=ed;
while(now!=st)
{
pre=path[now];
gra[pre][now]-=step;
gra[now][pre]+=step;
now=pre;
}
}
return max_flow;
} int main()
{
int i,u,v,cost,T,c,d,e,cas=;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(gra,,sizeof(gra));
for(i=;i<=m;i++)
{
scanf("%d%d%d",&c,&d,&e);
gra[c][d]+=e;
}
st=;ed=n;
printf("Case %d: %d\n",++cas,ek());
}
return ;
}
H - Farm Tour
To show off his farm in the best way, he walks a tour that
starts at his house, potentially travels through some fields, and ends
at the barn. Later, he returns (potentially through some fields) back to
his house again.
He wants his tour to be as short as possible, however he
doesn't want to walk on any given path more than once. Calculate the
shortest tour possible. FJ is sure that some tour exists for any given
farm.
Input
* Lines 2..M+1: Three space-separated integers that define a path: The starting field, the end field, and the path's length.
Output
Sample Input
4 5
1 2 1
2 3 1
3 4 1
1 3 2
2 4 2
Sample Output
6
建图:超级源点source,超级汇点sink
1,source连点1,容量为2,费用为0;
2,对题目给出的无向边<u, v>建双向边,容量为1(意味着该边只能走一次),费用为边的长度;
3,N到sink建边,容量为2,费用为0。
最后跑一次最小费用最大流就可以了。
#include <cstdio>
#include <cstring>
#include <queue>
#define MAXN 1010
#define MAXM 50000+10
using namespace std;
struct Edge
{
int from, to, cap, flow, cost, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int dist[MAXN];
int pre[MAXN];
bool vis[MAXN];
int N, M;
int source, sink;
void init()
{
edgenum = ;
memset(head, -, sizeof(head));
}
void addEdge(int u, int v, int w, int c) //加边uv
{
Edge E1 = {u, v, w, , c, head[u]};
edge[edgenum] = E1;
head[u] = edgenum++;
Edge E2 = {v, u, , , -c, head[v]};
edge[edgenum] = E2;
head[v] = edgenum++;
}
void getMap()
{
int a, b, c;
source = , sink = N+;
while(M--)
{
scanf("%d%d%d", &a, &b, &c);
addEdge(a, b, , c);//建双向边
addEdge(b, a, , c);
}
addEdge(source, , , );//超级源点连起点
addEdge(N, sink, , );//终点连超级汇点
}
bool SPFA(int s, int t) //spfa算法求最小流
{
queue<int> Q;
memset(dist, 0x3f3f3f3f, sizeof(dist));
memset(vis, false, sizeof(vis));
memset(pre, -, sizeof(pre));
dist[s] = ;
vis[s] = true;
Q.push(s);
while(!Q.empty())
{
int u = Q.front();
Q.pop();
vis[u] = false;
for(int i = head[u]; i != -; i = edge[i].next)
{
Edge E = edge[i];
if(dist[E.to] > dist[u] + E.cost && E.cap > E.flow)
{
dist[E.to] = dist[u] + E.cost;
pre[E.to] = i;
if(!vis[E.to])
{
vis[E.to] = true;
Q.push(E.to);
}
}
}
}
return pre[t] != -;
}
void MCMF(int s, int t, int &cost)//最小费用最大流算法
{
cost = ;
while(SPFA(s, t))
{
int Min = 0x3f3f3f3f;
for(int i = pre[t]; i != -; i = pre[edge[i^].to])
{
Edge E = edge[i];
Min = min(Min, E.cap - E.flow);
}
for(int i = pre[t]; i != -; i = pre[edge[i^].to])
{
edge[i].flow += Min;
edge[i^].flow -= Min;
cost += edge[i].cost * Min;
}
}
}
int main()
{
while(scanf("%d%d", &N, &M) != EOF)
{
init();
getMap();
int cost;//设置最小费用
MCMF(source, sink, cost);
printf("%d\n", cost);
}
return ;
}