您的位置:首页 > 理论基础 > 计算机网络

[HihoCoder1378]网络流二·最大流最小割定理

2017-07-28 16:00 295 查看

思路:

根据最大流最小割定理可得最大流与最小割相等,所以可以先跑一遍EdmondsKarp算法。
接下来要求的是经过最小割切割后的图中$S$所属的点集。
本来的思路是用并查集处理所有前向边构成的残量网络,如果当前边的残量不为零,则合并两个端点。
然而这样子会WA,因为这只适用于无向图的情况,而流网络属于有向图。
解决的方法是用一个DFS,处理出所有从$S$出发可到达的点,如果边的残量为零则说明当前边不可用。

#include<set>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
inline int getint() {
char ch;
while(!isdigit(ch=getchar()));
int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=501,M=20000,inf=0x7fffffff;
struct Edge {
int from,to,remain;
};
Edge e[M<<1];
std::vector<int> g
;
int sz=0;
inline void add_edge(const int u,const int v,const int w) {
e[sz]=(Edge){u,v,w};
g[u].push_back(sz);
sz++;
}
int n,m,s,t;
int a
,p
;
inline int Augment() {
memset(a,0,sizeof a);
a[s]=inf;
std::queue<int> q;
q.push(s);
while(!q.empty()&&!a[t]) {
int x=q.front();
q.pop();
for(unsigned i=0;i<g[x].size();i++) {
Edge &y=e[g[x][i]];
if(!a[y.to]&&y.remain) {
p[y.to]=g[x][i];
a[y.to]=std::min(a[x],y.remain);
q.push(y.to);
}
}
}
return a[t];
}
inline int EdmondsKarp() {
int maxflow=0;
while(int flow=Augment()) {
for(int i=t;i!=s;i=e[p[i]].from) {
e[p[i]].remain-=flow;
e[p[i]^1].remain+=flow;
}
maxflow+=flow;
}
return maxflow;
}
bool v
={0};
std::vector<int> ans;
inline void FindSet(const int x) {
v[x]=true;
ans.push_back(x);
for(unsigned int i=0;i<g[x].size();i++) {
if((g[x][i]&1)||v[e[g[x][i]].to]||!e[g[x][i]].remain) continue;
FindSet(e[g[x][i]].to);
}
}
int main() {
n=getint(),m=getint();
s=1,t=n;
while(m--) {
int u=getint(),v=getint(),w=getint();
add_edge(u,v,w);
add_edge(v,u,0);
}
printf("%d ",EdmondsKarp());
FindSet(s);
printf("%u\n",ans.size());
for(unsigned int i=0;i<ans.size()-1;i++) {
printf("%d ",ans[i]);
}
printf("%d\n",ans.back());
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: