hihoCoder 1378 网络流二·最大流最小割定理 (网络流学习#2 记录)
题目链接:http://hihocoder.com/problemset/problem/1378
代码:
#include<bits/stdc++.h> using namespace std; const int maxn=505; int c[maxn][maxn],pre[maxn],flow[maxn][maxn],INF=0x3f3f3f3f,n,vis[maxn]={0},flag=0,num=0; int bfs(int s,int t) { for(int i=1;i<=n;i++) pre[i]=-1; queue<int>q; q.push(s); int node; if(flag) vis[s]=1,num++; while(!q.empty()) { node=q.front(); q.pop(); for(int i=1;i<=n;i++) { if(flag==0&&pre[i]==-1&&c[node][i]-flow[node][i]>0) { pre[i]=node; if(flag==0&&i==t) return 1; q.push(i); } else if(flag&&pre[i]==-1&&c[node][i]>flow[node][i]) { pre[i]=node; if(vis[i]==0) vis[i]=1,num++; q.push(i); } } } return 0; } int dfs(int node,int v) { if(node==1) return v; v=dfs(pre[node],min(v,c[pre[node]][node]-flow[pre[node]][node])); flow[pre[node]][node]+=v; flow[node][pre[node]]-=v; return v; } int maxflow(int s,int t) { int tmp,ans=0; while(bfs(s,t)) { tmp=dfs(t,INF); ans+=tmp; } return ans; } int main() { int m; scanf("%d%d",&n,&m); int u,v,cc; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) c[i][j]=0,flow[i][j]=0; for(int i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&cc); c[u][v]+=cc; } printf("%d ",maxflow(1,n)); flag=1; flag=bfs(1,n); flag=1; printf("%d\n",num); for(int i=1;i<=n;i++) { if(vis[i]) { if(flag) flag=0; else printf(" "); printf("%d",i); } } puts(""); }
(邻接矩阵版)
#include<bits/stdc++.h> using namespace std; const int maxn=505,M=20005; struct node{ int v,c,flow,nxt; }edge[M*2]; int head[maxn],tot,n,vis[maxn],num,flag=0,INF=0x3f3f3f3f; void addnode(int u,int v,int c) { edge[tot].v=v; edge[tot].c=c; edge[tot].flow=0; edge[tot].nxt=head[u]; head[u]=tot++; edge[tot].v=u; edge[tot].c=0; edge[tot].flow=0; edge[tot].nxt=head[v]; head[v]=tot++; } int bfs() { memset(vis,0,sizeof(vis)); queue<int>q; q.push(1); vis[1]=1; if(flag) num++; while(!q.empty()) { int tmp=q.front(); q.pop(); for(int i=head[tmp];i!=-1;i=edge[i].nxt) { int c=edge[i].c,v=edge[i].v,f=edge[i].flow; if(vis[v]==0&&c-f>0) { vis[v]=vis[tmp]+1; if(flag==0&&v==n) return 1; if(flag)num++; q.push(v); } } } return 0; } int dfs(int x,int c) { int ans=0; if(x==n||c==0) return c; for(int i=head[x];i!=-1;i=edge[i].nxt) { int v=edge[i].v,cc=edge[i].c,f=edge[i].flow,kk; if(vis[v]==vis[x]+1) { kk=dfs(v,min(cc-f,c)); if(kk>0) { edge[i].flow+=kk; edge[i^1].flow-=kk; ans+=kk; c-=kk; if(c==0) break; } } } return ans; } int maxflow(int s,int t) { int ans=0; while(bfs()) { ans+=dfs(s,INF); } flag=1; flag=bfs(); return ans; } int main() { int m,u,v,c; tot=0; num=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) head[i]=-1; for(int i=0;i<m;i++) { scanf("%d%d%d",&u,&v,&c); addnode(u,v,c); } flag=0; printf("%d ",maxflow(1,n)); printf("%d\n",num); for(int i=1;i<=n;i++) { if(vis[i]) { if(!flag) flag=1; else printf(" "); printf("%d",i); } } puts(""); }
(邻接表版)
这个好像是当时看了题目一脸懵逼,然后后面看了一眼十佳代码,突然就明白了。。然后手打了两份。
也没仔细看思想是哪一个,之前看sap还是dinic是要分层的,,,看了一堆理论,说是优化ek就优化找增广路径。我想大概这就是所谓的dinic吧。
这题求的是最小割和割完后原点所在的集合点的个数和原点所在集合所有点。
flag就是判断是不是最后一遍搜索,最后一遍bfs就是为了求与s联通的点并标记,计数。