题源:https://nanti.jisuanke.com/t/11215
分析:这题是一个比较经典的网络流模型。把中间节点当做源,两端节点当做汇,对节点进行拆点,做一个流量为 22 的流即可。
吐槽:这是官方题解,然后其实赛场上谢了这个解法,但是我写搓了,因为最后输出路径的时候傻逼了
我居然向最短路一样记录前驱输出路径,简直傻逼了
着重强调(对我自己):网络流的一次增广是需要记录前驱的,但是多次增广以后,可以反向流,前驱就不对了
所以要判断哪些边,在最大流上时,需要枚举边,看哪个满流,然后随便搞搞
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <string>
#include <stack>
#include <vector>
#include <map>
#include <queue>
#include <algorithm>
#include <utility>
using namespace std;
typedef long long LL;
const int N=;
const int INF=0x3f3f3f3f;
int cap[N][N],flow[N][N],n,m,s,t;
bool vis[N];
int p[N],a[N];
void maxflow(int s,int t){
queue<int>q;
memset(flow,,sizeof(flow));
while(){
memset(a,,sizeof(a));
memset(vis,false,sizeof(vis));
while(!q.empty())q.pop();
a[s]=INF;q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
if(u==t)break;
for(int v=;v<=n*+;++v)
if(!a[v]&&flow[u][v]<cap[u][v]){
vis[v]=true;
p[v]=u;a[v]=min(a[u],cap[u][v]-flow[u][v]);
q.push(v);
}
}
if(!a[t])break;
for(int u=t;u!=s;u=p[u]){
flow[p[u]][u]+=a[t];
flow[u][p[u]]-=a[t];
}
}
}
struct Edge{
int v,next;
}edge[*];
int head[],tot;
void add(int u,int v){
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot++;
}
vector<int>ret;
void dfs(int u,int f){
ret.push_back(u);
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
if(v==f)continue;
dfs(v,u);
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--){
int a,b,mid;
scanf("%d%d%d%d%d",&n,&m,&a,&b,&mid);
s=,t=n*+;
memset(cap,,sizeof(cap));
for(int i=;i<m;++i){
int u,v;
scanf("%d%d",&u,&v);
cap[u+n][v]=cap[v+n][u]=;
}
for(int i=;i<=n;++i)
cap[i][i+n]=;
cap[s][mid]=cap[mid][mid+n]=;
cap[a+n][t]=cap[b+n][t]=;
maxflow(s,t);
memset(head,-,sizeof(head));tot=;
for(int i=+n;i<=n+n;++i){
if(!flow[i-n][i])continue;
for(int j=;j<=n;++j){
if(cap[i][j]&&flow[i][j]==cap[i][j]){
add(i-n,j);add(j,i-n);
}
}
}
ret.clear();
dfs(a,);
for(int i=;i<ret.size();++i){
printf("%d",ret[i]);
if(i+==ret.size())printf("\n");
else printf(" ");
}
}
return ;
}