最大流模板(修改版)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/*网络流中的最大流问题 即,给出一个图,图中每条边有一个容量,图中有两点分别为源点和汇点 在每条边流量不超过其容量的情况下,求解从原点开始能流到汇点的最大流量 dinic算法是一种基于增广路思想求解最大流的算法,其基本步骤为: 1、在图中找到一条从源点到汇点的路径, 使路径上每条边的残余流量re大于零,称这条路径为增广路。 2、取该路径上的最小re,记为re_min,并将答案max_flow加上re_min。 将这条路径上所有边的re都减去re_min,他们的反向边都加上re_min。 不停进行以上两个步骤直至图中没有增广路,最后得到的max_flow就是最大流。 下面是应用dinic算法求解最大流的代码。 */ #include<cstdio> #include<cstring> #include<queue> #include<cmath> #define maxn 10005 #define maxm 100005 using namespace std; const int inf=1<<30; int num,lst[maxn],cur[maxn],dep[maxn]; int s,t,n,m; queue<int>q; struct in { int to,nxt,re; }e[maxm]; void add(int x,int y,int z)//邻接表建图 { e[++num].to=y; e[num].nxt=lst[x]; lst[x]=num; e[num].re=z; } void clear() { num=-1;//从0开始为边编号 memset(lst,-1,sizeof(lst)); } int bfs()//广搜,进行图分层 { int i,u,v; while (!q.empty()) q.pop(); //清空队列 memset(dep,-1,sizeof(dep)); dep[s]=0; q.push(s); while(!q.empty()) { u=q.front(); q.pop(); for(i=lst[u];i!=-1;i=e[i].nxt) { v=e[i].to; if (e[i].re && dep[v]==-1)//如果该节点之前没有被搜索到并且不是反向边 { dep[v]=dep[u]+1;//更新该节点深度 q.push(v);//将该节点加入队列 } } } return dep[t]!=-1;//没有搜索到汇点就不存在增广路 } int dfs(int u,int flow)//寻找增广路并返回其流量 { //x表示当前节点,flow表示当前流到x的残量 if (u==t || !flow) return flow; int i,v,res,used=0;//used表示u节点总共流出的流量 for (i=cur[u];i!=-1;i=e[i].nxt) { v=e[i].to; cur[u]=i;//当前弧优化 if (dep[v]==dep[u]+1 && e[i].re)//v为u的下一层,且当前边有残量>0 { res=dfs(v,min(flow,e[i].re));//res表示当前边流出的流量 if (res) { used+=res; flow-=res; e[i].re-=res; e[i^1].re+=res;//i^1是i的反向边 if (!flow) return used;//流入当前点的流量流完了,退出 } } } if (flow) dep[u]=-1;//优化,流到u的流量会有冗余,这一轮dfs中就再也用不到u了(u已经无法流出更多流量) return used; } int dinic()//不停寻找增广路并更新答案,直至图中不存在增广路 { int i,maxflow=0; while (bfs()) { for (i=0;i<=max(n,t);i++) cur[i]=lst[i];//当前弧优化,重置cur maxflow+=dfs(s,inf);//加入寻找到的增广路的流量 } return maxflow; } int main() { int u,v,w,i; clear(); scanf("%d%d%d%d",&n,&m,&s,&t);//n节点数,m边数,s源点,t汇点 for(i=1;i<=m;i++)//读入m条边 { scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,0);//反向边 } printf("%d ",dinic()); return 0; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<queue> #include<cmath> #define maxn 10005 #define maxm 100005 using namespace std; const int inf=1<<30; int num,lst[maxn],cur[maxn],dep[maxn]; int s,t,n,m; queue<int>q; struct in { int to,nxt,re; }e[maxm]; void add(int x,int y,int z) { e[++num].to=y; e[num].nxt=lst[x]; lst[x]=num; e[num].re=z; } void clear() { num=-1; memset(lst,-1,sizeof(lst)); } int bfs() { int i,u,v; while (!q.empty()) q.pop(); memset(dep,-1,sizeof(dep)); dep[s]=0; q.push(s); while(!q.empty()) { u=q.front(); q.pop(); for(i=lst[u];i!=-1;i=e[i].nxt) { v=e[i].to; if (e[i].re && dep[v]==-1) { dep[v]=dep[u]+1; q.push(v); } } } return dep[t]!=-1; } int dfs(int u,int flow) { if (u==t || !flow) return flow; int i,v,res,used=0; for (i=cur[u];i!=-1;i=e[i].nxt) { v=e[i].to; cur[u]=i; if (dep[v]==dep[u]+1 && e[i].re) { res=dfs(v,min(flow,e[i].re)); if (res) { used+=res; flow-=res; e[i].re-=res; e[i^1].re+=res; if (!flow) return used; } } } if (flow) dep[u]=-1; return used; } int dinic() { int i,maxflow=0; while (bfs()) { for (i=0;i<=max(n,t);i++) cur[i]=lst[i]; maxflow+=dfs(s,inf); } return maxflow; } int main() { int u,v,w,i; clear(); scanf("%d%d%d%d",&n,&m,&s,&t); for(i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,0); } printf("%d ",dinic()); return 0; }
最大流最小费模板(修改spfa函数中的赋初值dis[i]=-inf与if (dis[v]<dis[u]+e[i].w)就可变为最大费用最大流。)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<queue> #include<cmath> #define maxn 10000 #define maxm 40000 using namespace std; const int inf=1<<30; int num,lst[maxn]; int pre[maxn],vis[maxn],flow[maxn],dis[maxn],from[maxn]; int tot1,tot2,q1[maxn][2],q2[maxn][2]; int s,t,n,m,lim; queue<int>q; struct in { int to,nxt,re,w; }e[maxm]; void add(int x,int y,int z,int w) { e[++num].to=y;e[num].nxt=lst[x];lst[x]=num;e[num].re=z;e[num].w=w; } void clear() { num=-1; memset(lst,-1,sizeof(lst)); } int spfa() { int i,u,v; while (!q.empty()) q.pop(); for (i=1;i<=t;++i) { pre[i]=-1; from[i]=-1; dis[i]=inf; vis[i]=0; } q.push(s); dis[s]=0; flow[s]=inf; vis[s]=1; while (!q.empty()) { u=q.front(); q.pop(); vis[u]=0; for (i=lst[u];i!=-1;i=e[i].nxt) { v=e[i].to; if (!e[i].re) continue; if (dis[v]>dis[u]+e[i].w) { dis[v]=dis[u]+e[i].w; flow[v]=min(e[i].re,flow[u]); pre[v]=i; from[v]=u; if (!vis[v]) { vis[v]=1; q.push(v); } } } } return pre[t]!=-1; } int mfmv() { int mincost=0,maxflow=0,v; while (spfa()) { mincost+=flow[t]*dis[t]; maxflow+=flow[t]; v=t; while (v!=s) { e[pre[v]].re-=flow[t]; e[pre[v]^1].re+=flow[t]; v=from[v]; } } return mincost; } int main() { int i,x,y,z,w; clear(); scanf("%d%d%d%d",&n,&m,&s,&t); for (i=1;i<=m;i++) { scanf("%d%d%d%d",&x,&y,&z,&w); add(x,y,z,w); add(y,x,0,-w); } printf("%d ",mfmv()); return 0; }
B HDU 3572
建图,将每一天j与源点s连边add(s,j,m),每个任务i与汇点t连边add(i,t,p),每个任务i与可以做这个任务的每一天j连边add(j,i,1)。然后求最大流,如果最大流等于所有任务所需的天数p之和,就YES,否则NO。
昨天折腾一晚上,不停TLE,然后加了一个优化(就是那个if (flow) dep[u]=-1的优化)过了。。行吧,修改了一下dinic模板。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<queue> #include<cmath> #define maxn 1010 #define maxm 500005 #define inf 0x3f3f3f3f using namespace std; int num,lst[maxn],dep[maxn],mark[maxn],cur[maxn]; int s,t,n; queue<int>q; struct in { int to,nxt,re; }e[maxm]; void add(int x,int y,int z) { e[++num].to=y;e[num].nxt=lst[x];lst[x]=num;e[num].re=z; e[++num].to=x;e[num].nxt=lst[y];lst[y]=num;e[num].re=0; } void clear() { num=-1;//从0开始为边编号 memset(lst,-1,sizeof(lst)); } int bfs()//广搜,进行图分层 { int i,u,v; while (!q.empty()) q.pop(); //清空队列 memset(dep,-1,sizeof(dep)); dep[s]=0; q.push(s); while(!q.empty()) { u=q.front(); q.pop(); for(i=lst[u];i!=-1;i=e[i].nxt) { v=e[i].to; if (e[i].re && dep[v]==-1)//如果该节点之前没有被搜索到并且不是反向边 { dep[v]=dep[u]+1;//更新该节点深度 q.push(v);//将该节点加入队列 } } } return dep[t]!=-1;//没有搜索到汇点就不存在增广路 } int dfs(int u,int flow)//寻找增广路并返回其流量 { //x表示当前节点,flow表示当前流到x的残量 if (u==t || !flow) return flow; int i,v,res,used=0;//used表示u节点总共流出的流量 for (i=cur[u];i!=-1;i=e[i].nxt) { v=e[i].to; cur[u]=i;//当前弧优化 if (dep[v]==dep[u]+1 && e[i].re)//v为u的下一层,且当前边有残量>0 { res=dfs(v,min(flow,e[i].re));//res表示当前边流出的流量 if (res) { used+=res; flow-=res; e[i].re-=res; e[i^1].re+=res;//i^1是i的反向边 if (!flow) return used;//流入当前点的流量流完了,退出 } } } if (flow) dep[u]=-1;//优化,流到u的流量会有冗余,这一轮dfs中就再也用不到u了(u已经无法流出更多流量) return used; } int dinic()//不停寻找增广路并更新答案,直至图中不存在增广路 { int i,maxflow=0; while (bfs()) { for (i=0;i<=max(n,t);i++) cur[i]=lst[i];//当前弧优化,重置cur maxflow+=dfs(s,inf);//加入寻找到的增广路的流量 } return maxflow; } int main() { int i,j,k,x,y,z,T,m,sum,note=1; int maxflow,flow; scanf("%d",&T); for (k=1;k<=T;k++) { scanf("%d%d",&n,&m); s=0;t=500+n+1; clear(); sum=0; memset(mark,0,sizeof(mark)); for (i=1;i<=n;i++) { scanf("%d%d%d",&x,&y,&z); for (j=y;j<=z;j++) { mark[j]=1; add(j,i+500,1); } add(i+500,t,x); sum+=x; } for (i=1;i<=500;i++) { if (!mark[i]) continue; add(s,i,m); } if (dinic()==sum) printf("Case %d: Yes ",k); else printf("Case %d: No ",k); } return 0; }