最近在老师的带领下学习了网络流,认真的搞啊搞,终于懂了基础模板
先上一发dinic(没有带当前弧优化哦)不过看者还是挺快的;
#include<queue> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int N=1001010; const int INF=1e9; int m,n,s,t,cnt=-1,head[N],ans,dep[N]; struct edge { int to,nx,flow;} e[N]; void add_edge(int u,int v,int w) { cnt++; e[cnt].to=v; e[cnt].flow=w; e[cnt].nx=head[u]; head[u]=cnt; } bool bfs(int s,int t) { queue<int> que; memset(dep,0,sizeof(dep)); dep[s]=1;que.push(s); while (!que.empty()) { int x=que.front();que.pop(); for (int i=head[x];i!=-1;i=e[i].nx) { int y=e[i].to; if (dep[y]==0&&e[i].flow>0) { dep[y]=dep[x]+1; que.push(y); } } } if (dep[t]>0) return true; else return false; } int dfs(int x,int limit,int t) { if (x==t) return limit; for (int i=head[x];i!=-1;i=e[i].nx) { int y=e[i].to; if (dep[y]==dep[x]+1&&e[i].flow>0) { int di=dfs(y,min(limit,e[i].flow),t); if (di>0) { e[i].flow-=di; e[i^1].flow+=di; return di; } } } return 0; } void dinic(int s,int t) { while (bfs(s,t)) ans+=dfs(s,INF,t); } int main() { freopen("ditch.in","r",stdin); freopen("ditch.out","w",stdout); scanf("%d%d",&m,&n); memset(head,-1,sizeof(head)); for (int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); add_edge(x,y,z); add_edge(y,x,0); } dinic(1,n); printf("%d",ans); return 0; }
用的是草地排水这道题来作例子,其实模板啥的,看懂思路背一背就好了
然后就是最小费用最大流
洛谷的模板
#include<bits/stdc++.h> using namespace std; const int N=100010; const int INF=0x7fffffff; int dis[N],flow[N],cnt=-1,head[N],m,n,s,t,pre[N],last[N],mincost,maxflow; bool inque[N]; struct edge { int to,nx,dist,flow;} e[N]; void add_edge(int u,int v,int w,int f) { cnt++; e[cnt].flow=w; e[cnt].dist=f; e[cnt].to=v; e[cnt].nx=head[u]; head[u]=cnt; } bool SPFA(int s,int t) { for (int i=1;i<=N;i++) dis[i]=INF; for (int i=1;i<=N;i++) flow[i]=INF; memset(inque,0,sizeof(inque)); queue<int> que;que.push(s);inque[s]=true;pre[t]=-1;dis[s]=0; while (!que.empty()) { int x=que.front();que.pop();inque[x]=false; for (int i=head[x];i!=-1;i=e[i].nx) { int y=e[i].to; if (dis[y]>dis[x]+e[i].dist&&e[i].flow>0) { dis[y]=dis[x]+e[i].dist; pre[y]=x; last[y]=i; flow[y]=min(flow[x],e[i].flow); if (!inque[y]) { que.push(y);inque[y]=true;} } } } if (pre[t]==-1) return false; else return true; } void MCMF(int s,int t) { while (SPFA(s,t)) { int x=t; maxflow+=flow[t]; mincost+=dis[t]*flow[t]; while (x!=s) { e[last[x]].flow-=flow[t]; e[last[x]^1].flow+=flow[t]; x=pre[x]; } } } int main() { scanf("%d%d%d%d",&n,&m,&s,&t); memset(head,-1,sizeof(head)); for (int i=1;i<=m;i++) { int x,y,z,f; scanf("%d%d%d%d",&x,&y,&z,&f); add_edge(x,y,z,f);add_edge(y,x,0,-f); } MCMF(s,t); printf("%d %d",maxflow,mincost); return 0; }
进入今天的正题,追查坏牛奶
思想的话不会人家的玄学求最小割的边数,于是自己想了个神奇的乱搞,先求出最大流,即最小割,然后枚举每条边看是否完全属于割集,然后将其永久去掉
然后将整个输出即可,代码纯属原创
#include<bits/stdc++.h> using namespace std; #define ll long long const int N=100010; const ll INF=0x7ffffffff; ll m,n,s,t,pre[N],head[N],cnt=1,last[N],dep[N],tot,sum[N],ans,Ans,ff; struct edge { ll from,to,nx,flow;} e[N]; struct node { ll x,y,z;} kk[N]; void add_edge(ll from,ll to,ll flow) { cnt++;e[cnt].from=from;e[cnt].flow=flow; e[cnt].nx=head[from];e[cnt].to=to;head[from]=cnt; cnt++;e[cnt].flow=0;e[cnt].to=from; e[cnt].from=to;e[cnt].nx=head[to];head[to]=cnt; } bool bfs(int s,int t) { memset(dep,0,sizeof(dep)); queue<ll> que;dep[s]=1;que.push(s); while (!que.empty()) { ll x=que.front();que.pop(); for (ll i=head[x];i;i=e[i].nx) { ll y=e[i].to; if (dep[y]==0&&e[i].flow>0) { dep[y]=dep[x]+1; que.push(y); } } } if (dep[t]==0) return false; else return true; } ll dfs(int x,ll limit,int t) { if(x==t) return limit; ll used=0; for (ll i=head[x];i;i=e[i].nx) { ll y=e[i].to; if (dep[y]==dep[x]+1&&e[i].flow>0) { ll di=dfs(y,min(limit-used,e[i].flow),t); if (di>0) { e[i].flow-=di; e[i^1].flow+=di; used+=di; if (used==limit) return used; } } } if (!used) dep[x]=-2; return used; } void dinic() { while (bfs(1,n)) ans+=dfs(1,INF,n);} void cs() { ans=0;cnt=1;memset(head,0,sizeof(head)); for (int j=1;j<=m;j++) add_edge(kk[j].x,kk[j].y,kk[j].z); for (int k=1;k<=tot;k++) {e[sum[k]*2].flow=0;} } int main() { scanf("%lld%lld",&n,&m); for (ll i=1;i<=m;i++) { ll x,y,z; scanf("%lld%lld%lld",&x,&y,&z); kk[i].x=x;kk[i].y=y;kk[i].z=z; add_edge(x,y,z); } dinic();ff=ans;Ans=ans; for (int i=1;i<=m;i++) { cs(); ll f=e[i*2].flow; e[i*2].flow=0; dinic(); if (ans==0&&f==ff) {tot=1;sum[tot]=i;break;} if (ans+f==Ans) {tot++;sum[tot]=i;Ans=ans;} } printf("%lld %lld ",ff,tot); for (int i=1;i<=tot;i++) printf("%lld ",sum[i]); return 0; }
hale会越来越棒的