1、看了好久,囧。

n个节点,np个源点,nc个汇点,m条边(对应代码中即节点u 到节点v 的最大流量为z)

求所有汇点的最大流。

2、多个源点,多个汇点的最大流。

建立一个超级源点、一个超级汇点,然后求超级源点到超级汇点的最大流即可。

3、

1、SAP邻接矩阵形式:

/*
SAP算法(矩阵形式)
结点编号从0开始
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std; const int MAXN=;
int maze[MAXN][MAXN];
int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN];
int sap(int start,int end,int nodenum){
memset(cur,,sizeof(cur));
memset(dis,,sizeof(dis));
memset(gap,,sizeof(gap));
int u=pre[start]=start,maxflow=,aug=-;
gap[]=nodenum;
while(dis[start]<nodenum){
loop:
for(int v=cur[u];v<nodenum;v++)
if(maze[u][v]&&dis[u]==dis[v]+){
if(aug==-||aug>maze[u][v])aug=maze[u][v];
pre[v]=u;
u=cur[u]=v;
if(v==end){
maxflow+=aug;
for(u=pre[u];v!=start;v=u,u=pre[u]){
maze[u][v]-=aug;
maze[v][u]+=aug;
}
aug=-;
}
goto loop;
}
int mindis=nodenum-;
for(int v=;v<nodenum;v++)
if(maze[u][v]&&mindis>dis[v]){
cur[u]=v;
mindis=dis[v];
}
if((--gap[dis[u]])==)break;
gap[dis[u]=mindis+]++;
u=pre[u];
}
return maxflow;
} int main(){
int n,np,nc,m;//节点总数,源点,汇点,边数
int u,v,z;//节点u,节点v,最大流量z
char str[];//处理空格
int sp,sc;//超级源点,超级汇点 while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){
memset(maze,,sizeof(maze));
for(int i=;i<m;++i){
scanf("%1s%d%1s%d%1s%d",str,&u,str,&v,str,&z);
maze[u][v]=z;
} //建立超级源点
sp=n++;
for(int i=;i<np;++i){
scanf("%1s%d%1s%d",str,&u,str,&z);
maze[sp][u]=z;
}
//建立超级汇点
sc=n++;
for(int i=;i<nc;++i){
scanf("%1s%d%1s%d",str,&u,str,&z);
maze[u][sc]=z;
}
printf("%d\n",sap(sp,sc,n));
}
return ;
}

2、SAP邻接矩阵形式2:

/*
保留原矩阵,可用于多次使用最大流
SAP邻接矩阵形式
点的编号从0开始
增加个flow数组,保留原矩阵maze,可用于多次使用最大流
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std; const int MAXN=;
int maze[MAXN][MAXN];
int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN];
int flow[MAXN][MAXN];//存最大流的容量
int sap(int start,int end,int nodenum){
memset(cur,,sizeof(cur));
memset(dis,,sizeof(dis));
memset(gap,,sizeof(gap));
memset(flow,,sizeof(flow));
int u=pre[start]=start,maxflow=,aug=-;
gap[]=nodenum;
while(dis[start]<nodenum){
loop:
for(int v=cur[u];v<nodenum;v++)
if(maze[u][v]-flow[u][v]&&dis[u]==dis[v]+){
if(aug==-||aug>maze[u][v]-flow[u][v])aug=maze[u][v]-flow[u][v];
pre[v]=u;
u=cur[u]=v;
if(v==end){
maxflow+=aug;
for(u=pre[u];v!=start;v=u,u=pre[u]){
flow[u][v]+=aug;
flow[v][u]-=aug;
}
aug=-;
}
goto loop;
}
int mindis=nodenum-;
for(int v=;v<nodenum;v++)
if(maze[u][v]-flow[u][v]&&mindis>dis[v]){
cur[u]=v;
mindis=dis[v];
}
if((--gap[dis[u]])==)break;
gap[dis[u]=mindis+]++;
u=pre[u];
}
return maxflow;
} int main(){
int n,np,nc,m;//节点总数,源点,汇点,边数
int u,v,z;//节点u,节点v,最大流量z
char str[];//处理空格
int sp,sc;//超级源点,超级汇点 while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){
memset(maze,,sizeof(maze));
for(int i=;i<m;++i){
scanf("%1s%d%1s%d%1s%d",str,&u,str,&v,str,&z);
maze[u][v]=z;
} //建立超级源点
sp=n++;
for(int i=;i<np;++i){
scanf("%1s%d%1s%d",str,&u,str,&z);
maze[sp][u]=z;
}
//建立超级汇点
sc=n++;
for(int i=;i<nc;++i){
scanf("%1s%d%1s%d",str,&u,str,&z);
maze[u][sc]=z;
}
printf("%d\n",sap(sp,sc,n));
}
return ;
}

3、ISAP邻接表形式:注意一下边数的范围

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std; const int MAXN=;//点数的最大值
const int MAXM=;//边数的最大值(加的双向加,所以是2倍,别忘了加上超级源点和超级汇点(共400条))
const int INF=0x3f3f3f3f;
struct Edge{
int to,next,cap,flow;
}edge[MAXM];//注意是MAXM
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];
void init(){
tol=;
memset(head,-,sizeof(head));
}
//加边,单向图三个参数,双向图四个参数
void addedge(int u,int v,int w,int rw=){
edge[tol].to=v;edge[tol].cap=w;edge[tol].next=head[u];
edge[tol].flow=;head[u]=tol++;
edge[tol].to=u;edge[tol].cap=rw;edge[tol].next=head[v];
edge[tol].flow=;head[v]=tol++;
}
//输入参数:起点、终点、点的总数
//点的编号没有影响,只要输入点的总数
int sap(int start,int end,int N){
memset(gap,,sizeof(gap));
memset(dep,,sizeof(dep));
memcpy(cur,head,sizeof(head));
int u=start;
pre[u]=-;
gap[]=N;
int ans=;
while(dep[start]<N){
if(u==end){
int Min=INF;
for(int i=pre[u];i!=-;i=pre[edge[i^].to])
if(Min>edge[i].cap-edge[i].flow)
Min=edge[i].cap-edge[i].flow;
for(int i=pre[u];i!=-;i=pre[edge[i^].to]){
edge[i].flow+=Min;
edge[i^].flow-=Min;
}
u=start;
ans+=Min;
continue;
}
bool flag=false;
int v;
for(int i=cur[u];i!=-;i=edge[i].next){
v=edge[i].to;
if(edge[i].cap-edge[i].flow&&dep[v]+==dep[u]){
flag=true;
cur[u]=pre[v]=i;
break;
}
}
if(flag){
u=v;
continue;
}
int Min=N;
for(int i=head[u];i!=-;i=edge[i].next)
if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min){
Min=dep[edge[i].to];
cur[u]=i;
}
gap[dep[u]]--;
if(!gap[dep[u]])return ans;
dep[u]=Min+;
gap[dep[u]]++;
if(u!=start)u=edge[pre[u]^].to;
}
return ans;
} int main(){
int n,np,nc,m;//节点总数,源点,汇点,边数
int u,v,z;//节点u,节点v,最大流量z
char str[];//处理空格
int sp,sc;//超级源点,超级汇点 while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){
init();
for(int i=;i<m;++i){
scanf("%1s%d%1s%d%1s%d",str,&u,str,&v,str,&z);
addedge(u,v,z);
} //建立超级源点
sp=n++;
for(int i=;i<np;++i){
scanf("%1s%d%1s%d",str,&u,str,&z);
addedge(sp,u,z);
}
//建立超级汇点
sc=n++;
for(int i=;i<nc;++i){
scanf("%1s%d%1s%d",str,&u,str,&z);
addedge(u,sc,z);
}
printf("%d\n",sap(sp,sc,n));
}
return ;
}

4、ISAP+bfs初始化+栈优化:注意一下边数的范围

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std; const int MAXN=;//点数的最大值
const int MAXM=;//边数的最大值
const int INF=0x3f3f3f3f;
struct Edge{
int to,next,cap,flow;
}edge[MAXM];//注意是MAXM
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],cur[MAXN];
void init(){
tol=;
memset(head,-,sizeof(head));
}
void addedge(int u,int v,int w,int rw=){
edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=;
edge[tol].next=head[u];head[u]=tol++;
edge[tol].to=u;edge[tol].cap=rw;edge[tol].flow=;
edge[tol].next=head[v];head[v]=tol++;
}
int Q[MAXN];
void BFS(int start,int end){
memset(dep,-,sizeof(dep));
memset(gap,,sizeof(gap));
gap[]=;
int front=,rear=;
dep[end]=;
Q[rear++]=end;
while(front!=rear){
int u=Q[front++];
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].to;
if(dep[v]!=-)continue;
Q[rear++]=v;
dep[v]=dep[u]+;
gap[dep[v]]++;
}
}
}
int S[MAXN];
int sap(int start,int end,int N){
BFS(start,end);
memcpy(cur,head,sizeof(head));
int top=;
int u=start;
int ans=;
while(dep[start]<N){
if(u==end){
int Min=INF;
int inser;
for(int i=;i<top;i++)
if(Min>edge[S[i]].cap-edge[S[i]].flow){
Min=edge[S[i]].cap-edge[S[i]].flow;
inser=i;
}
for(int i=;i<top;i++){
edge[S[i]].flow+=Min;
edge[S[i]^].flow-=Min;
}
ans+=Min;
top=inser;
u=edge[S[top]^].to;
continue;
}
bool flag=false;
int v;
for(int i=cur[u];i!=-;i=edge[i].next){
v=edge[i].to;
if(edge[i].cap-edge[i].flow&&dep[v]+==dep[u]){
flag=true;
cur[u]=i;
break;
}
}
if(flag){
S[top++]=cur[u];
u=v;
continue;
}
int Min=N;
for(int i=head[u];i!=-;i=edge[i].next)
if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min){
Min=dep[edge[i].to];
cur[u]=i;
}
gap[dep[u]]--;
if(!gap[dep[u]])return ans;
dep[u]=Min+;
gap[dep[u]]++;
if(u!=start)u=edge[S[--top]^].to;
}
return ans;
} int main(){
int n,np,nc,m;//节点总数,源点,汇点,边数
int u,v,z;//节点u,节点v,最大流量z
char str[];//处理空格
int sp,sc;//超级源点,超级汇点 while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){
init();
for(int i=;i<m;++i){
scanf("%1s%d%1s%d%1s%d",str,&u,str,&v,str,&z);
addedge(u,v,z);
} //建立超级源点
sp=n++;
for(int i=;i<np;++i){
scanf("%1s%d%1s%d",str,&u,str,&z);
addedge(sp,u,z);
}
//建立超级汇点
sc=n++;
for(int i=;i<nc;++i){
scanf("%1s%d%1s%d",str,&u,str,&z);
addedge(u,sc,z);
}
printf("%d\n",sap(sp,sc,n));
}
return ;
}

5、dinic:注意一下边数的范围

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std; const int MAXN=;//点数的最大值
const int MAXM=;//边数的最大值
const int INF=0x3f3f3f3f;
struct Edge{
int to,next,cap,flow;
}edge[MAXM];//注意是MAXM
int tol;
int head[MAXN];
void init(){
tol=;
memset(head,-,sizeof(head));
}
void addedge(int u,int v,int w,int rw=){
edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=;
edge[tol].next=head[u];head[u]=tol++;
edge[tol].to=u;edge[tol].cap=rw;edge[tol].flow=;
edge[tol].next=head[v];head[v]=tol++;
}
int Q[MAXN];
int dep[MAXN],cur[MAXN],sta[MAXN];
bool bfs(int s,int t,int n){
int front=,tail=;
memset(dep,-,sizeof(dep[])*(n+));
dep[s]=;
Q[tail++]=s;
while(front<tail){
int u=Q[front++];
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].to;
if(edge[i].cap>edge[i].flow&&dep[v]==-){
dep[v]=dep[u]+;
if(v==t)return true;
Q[tail++]=v;
}
}
}
return false;
}
int dinic(int s,int t,int n){
int maxflow=;
while(bfs(s,t,n)){
for(int i=;i<n;i++)cur[i]=head[i];
int u=s,tail=;
while(cur[s]!=-){
if(u==t){
int tp=INF;
for(int i=tail-;i>=;i--)
tp=min(tp,edge[sta[i]].cap-edge[sta[i]].flow);
maxflow+=tp;
for(int i=tail-;i>=;i--){
edge[sta[i]].flow+=tp;
edge[sta[i]^].flow-=tp;
if(edge[sta[i]].cap-edge[sta[i]].flow==)
tail=i;
}
u=edge[sta[tail]^].to;
}
else if(cur[u]!=-&&edge[cur[u]].cap>edge[cur[u]].flow&&dep[u]+==dep[edge[cur[u]].to]){
sta[tail++]=cur[u];
u=edge[cur[u]].to;
}
else{
while(u!=s&&cur[u]==-)
u=edge[sta[--tail]^].to;
cur[u]=edge[cur[u]].next;
}
}
}
return maxflow;
} int main(){
int n,np,nc,m;//节点总数,源点,汇点,边数
int u,v,z;//节点u,节点v,最大流量z
char str[];//处理空格
int sp,sc;//超级源点,超级汇点 while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){
init();
for(int i=;i<m;++i){
scanf("%1s%d%1s%d%1s%d",str,&u,str,&v,str,&z);
addedge(u,v,z);
} //建立超级源点
sp=n++;
for(int i=;i<np;++i){
scanf("%1s%d%1s%d",str,&u,str,&z);
addedge(sp,u,z);
}
//建立超级汇点
sc=n++;
for(int i=;i<nc;++i){
scanf("%1s%d%1s%d",str,&u,str,&z);
addedge(u,sc,z);
}
printf("%d\n",dinic(sp,sc,n));
}
return ;
}

以上算法均取自kuangbin模板,ac时间均不到100ms。

下面补上一个增广路算法(EdmondsKarp算法),但是时间让人捉急,1000多ms

6、增广路算法(EdmondsKarp算法):

#include<iostream>
#include<stdio.h>
#include<vector>
#include<string.h>
#include<queue>
using namespace std; const int maxn=;
const int INF=0x3f3f3f3f; struct Edge{
int from,to,cap,flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
}; struct EdmondsKarp{
int n,m;//n好像没用到
vector<Edge>edges;//边数的两倍
vector<int>G[maxn];//邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
int a[maxn];//当起点到i的可改进量
int p[maxn];//最短路树上p的入弧编号 void init(int n){
for(int i=;i<n;i++)G[i].clear();
edges.clear();
} void AddEdge(int from,int to,int cap){
edges.push_back(Edge(from,to,cap,));
edges.push_back(Edge(to,from,,));//反向弧
m=edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
} int Maxflow(int s,int t){
int flow=;
for(;;){
memset(a,,sizeof(a));
queue<int>Q;
Q.push(s);
a[s]=INF;
while(!Q.empty()){
int x=Q.front();Q.pop();
for(int i=;i<G[x].size();i++){
Edge &e=edges[G[x][i]];
if(!a[e.to]&&e.cap>e.flow){
p[e.to]=G[x][i];
a[e.to]=min(a[x],e.cap-e.flow);
Q.push(e.to);
}
}
if(a[t])break;
}
if(!a[t])break;
for(int u=t;u!=s;u=edges[p[u]].from){
edges[p[u]].flow+=a[t];
edges[p[u]^].flow-=a[t];
}
flow+=a[t];
}
return flow;
}
}EK; int main(){
int n,np,nc,m;//节点总数,源点,汇点,边数
int u,v,z;//节点u,节点v,最大流量z
char str[];//处理空格
int sp,sc;//超级源点,超级汇点 while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){
EK.init(n+);//加上下面增加的超级源点和超级汇点
for(int i=;i<m;++i){
scanf("%1s%d%1s%d%1s%d",str,&u,str,&v,str,&z);
EK.AddEdge(u,v,z);
} //建立超级源点
sp=n++;
for(int i=;i<np;++i){
scanf("%1s%d%1s%d",str,&u,str,&z);
EK.AddEdge(sp,u,z);
}
//建立超级汇点
sc=n++;
for(int i=;i<nc;++i){
scanf("%1s%d%1s%d",str,&u,str,&z);
EK.AddEdge(u,sc,z);
}
printf("%d\n",EK.Maxflow(sp,sc));
}
return ;
}

POJ - 1459 Power Network(最大流)(模板)的更多相关文章

  1. POJ 1459 Power Network 最大流(Edmonds_Karp算法)

    题目链接: http://poj.org/problem?id=1459 因为发电站有多个,所以需要一个超级源点,消费者有多个,需要一个超级汇点,这样超级源点到发电站的权值就是发电站的容量,也就是题目 ...

  2. POJ 1459 Power Network / HIT 1228 Power Network / UVAlive 2760 Power Network / ZOJ 1734 Power Network / FZU 1161 (网络流,最大流)

    POJ 1459 Power Network / HIT 1228 Power Network / UVAlive 2760 Power Network / ZOJ 1734 Power Networ ...

  3. poj 1459 Power Network

    题目连接 http://poj.org/problem?id=1459 Power Network Description A power network consists of nodes (pow ...

  4. 2018.07.06 POJ 1459 Power Network(多源多汇最大流)

    Power Network Time Limit: 2000MS Memory Limit: 32768K Description A power network consists of nodes ...

  5. POJ 1459 Power Network(网络流 最大流 多起点,多汇点)

    Power Network Time Limit: 2000MS   Memory Limit: 32768K Total Submissions: 22987   Accepted: 12039 D ...

  6. 网络流--最大流--POJ 1459 Power Network

    #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #incl ...

  7. poj 1459 Power Network : 最大网络流 dinic算法实现

    点击打开链接 Power Network Time Limit: 2000MS   Memory Limit: 32768K Total Submissions: 20903   Accepted:  ...

  8. poj 1459 Power Network【建立超级源点,超级汇点】

    Power Network Time Limit: 2000MS   Memory Limit: 32768K Total Submissions: 25514   Accepted: 13287 D ...

  9. POJ 1459 Power Network(网络最大流,dinic算法模板题)

    题意:给出n,np,nc,m,n为节点数,np为发电站数,nc为用电厂数,m为边的个数.      接下来给出m个数据(u,v)z,表示w(u,v)允许传输的最大电力为z:np个数据(u)z,表示发电 ...

随机推荐

  1. Java日志实战及解析 - 引导

    日志是什么? 程序日志的作用 记录程序运行情况,程序员观察和调试使用 统计分析 日后审计 程序员,开发工程师,架构师等天天打交道. 实际中有4%的代码是日志! http://logging.apach ...

  2. NYOJ-673悟空的难题~~水题~~

    悟空的难题 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 自从悟空当上了齐天大圣,花果山上的猴子猴孙们便也可以尝到天上的各种仙果神酒,所以猴子猴孙们的体质也得到了很好的 ...

  3. 【python可视化系列】python数据可视化利器--pyecharts

    学可视化就跟学弹吉他一样,刚开始你会觉得自己弹出来的是噪音,也就有了在使用python可视化的时候,总说,我擦,为啥别人画的图那么溜: [python可视化系列]python数据可视化利器--pyec ...

  4. HDU1002 大数相加

    #include <iostream> #include <iostream> #include <iomanip> #include<string> ...

  5. Linux(3):linux目录结构

    查看系统版本: [root@neo ~]# cat /etc/redhat-release CentOS release 6.9 (Final) [root@neo ~]# uname -r 2.6. ...

  6. 【转载】ubuntu16.04 无线/Wifi 上网速度慢的解决方法

    原文链接:http://tieba.baidu.com/p/4737599703[侵删] 一直以为是域名解析的问题,可也觉得不像.今天在百度搜索“ubuntu16.04域名解析慢”的时候无意中看到了h ...

  7. c++ 实现 key-value缓存数据结构

    c++ 实现 key-value缓存数据结构 概述 最近在阅读Memcached的源代码,今天借鉴部分设计思想简单的实现了一个keyvalue缓存. 哈希表部分使用了unordered_map,用于实 ...

  8. MySQL错误日志、binlog日志、查询日志、慢查询日志简介

    1.数据库的日志是帮助数据库管理员,追踪分析数据库曾经发生的各种事件的有力依据,mysql中提供了错误日志.binlog日志(二进制日志).查处日志.慢查询日志.在此,我力求解决以下问题:各个日志的作 ...

  9. dubbo-admin安装和使用

    更新下链接,不知道是不是这个项目合入Apache的缘故,链接都变成了https://github.com/apache/incubator-dubbo/ 按照常理,直接去 https://github ...

  10. Jekyll 搭建

    Jekyll搭建个人主页 早上昨晚上弄hexo的时候就开始有问题,发现命令有错误!今天早上来就开始把另外建立了仓库,转Jekyll,并不顺利,做了一天了,基本的theme的本地和远端主页可以显示,但当 ...