题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1421
PDF的题,自己点链接把。。。
题目大意,给出一个无向图,然后输出将1,2点分成两个区域的最小的割的边;
最小割=最大流,跑完最大流之后,一部分的点能与 源 相连,但是另一部分只能与 汇 相连,中间空出来的那个线段就是最小割的线段,将能与 源 相连的点标记出来,然后遍历所有的边,发现有两个点(一个与 源 连 一个不与 源 连 )就是一条割边
遍历输出即可;
ac:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
//#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define mod 998244353
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
struct dot{
int x,y;
}d[100010];
struct node{
int v,w,cost,nxt;
node(int _v=0,int _w=0,int _nxt=0):
v(_v),w(_w),nxt(_nxt){}
}edge[100010];
int head[100010],e;
int dis[100010];
bool cut_vis[100010];
int n,m,s,t;
void intt()
{
clean(head,-1);
clean(cut_vis,0);
e=0;
}
void add(int u,int v,int w)
{
edge[e]=node(v,w,head[u]);
head[u]=e++;
edge[e]=node(u,w,head[v]);
head[v]=e++;
}
/*---上面的是板子,不用动---*/
bool bfs()
{
clean(dis,-1);
dis[s]=0;
queue<int> que;
que.push(s);
while(que.size())
{
int u=que.front();
que.pop();
if(u==t)
return 1;
for(int i=head[u];i+1;i=edge[i].nxt)
{
int temp=edge[i].v;
if(dis[temp]==-1&&edge[i].w)
{
dis[temp]=dis[u]+1;
que.push(temp);
}
}
}
return 0;
}
int dfs(int u,int low)//易错点,dis==dis+1!!
{
if(u==t||low==0)
return low;
int res=0;
for(int i=head[u];i+1;i=edge[i].nxt)
{
int temp=edge[i].v;
if(dis[temp]==dis[u]+1&&edge[i].w>0)
{
int f=dfs(temp,min(low-res,edge[i].w));
if(f>0)
{
edge[i].w-=f;
edge[i^1].w+=f;
res+=f;
if(res==low)
break;
}
}
}
return res;
}
void dinic()
{
int ans=0,res;
while(bfs())
{
while(res=dfs(s,INF))
ans+=res;
}
//cout<<ans<<endl;
}
/*---------Dinic的板子,也不用动*/
void cut_dfs(int u)//起点能到的都加进去
{
cut_vis[u]=1;
for(int i=head[u];i+1;i=edge[i].nxt)
{
int temp=edge[i].v;
if(edge[i].w>0&&cut_vis[temp]==0)
cut_dfs(temp);
}
}
//-----只招与源相连的点---
int main()
{
while(cin>>n>>m&&n!=0)
{
intt();
int num;
for(int i=1;i<=m;++i)
{
cin>>d[i].x>>d[i].y;
cin>>num;
add(d[i].x,d[i].y,num);
}
s=1,t=2;
dinic();
//-----下面就是遍历了,上面是板子
cut_dfs(s);
for(int i=1;i<=m;++i)
{
int u=d[i].x,v=d[i].y;
if((cut_vis[u]==0&&cut_vis[v])||(cut_vis[u]&&cut_vis[v]==0))
cout<<u<<" "<<v<<endl;
}
cout<<endl;
}
}
补充:
看见有dalao将Dinic用的更加自然,矩阵+Dinic放在一个函数中,直接跑while,没有递归,感觉很棒,学习一波,然后发现确实很不错,代码长度和复杂度都很小
ac:
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<map>
//#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define mod 998244353
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
//std::ios::sync_with_stdio(false);
int mp[1000][1000],flow[1000][1000];
int pre[1000],res[1000];
//父节点 min
int n,m;
int s,t;
void maxflow()
{
clean(flow,0);
int ans=0;
while(1)
{
clean(res,0);//BFS
res[s]=INF;
queue<int> que;
que.push(s);
while(que.size())//分层查找父节点
{
int u=que.front();
que.pop();
//if(u==t) break;
for(int i=1;i<=n;++i)//遍历城市
{
if(res[i]==0&&flow[u][i]<mp[u][i])
{
pre[i]=u;//直接记录父节点
res[i]=min(res[u],mp[u][i]-flow[u][i]);
que.push(i);
}
}
}
if(res[t]==0)
break;
//DFS()
for(int u=t;u!=s;u=pre[u])
{
flow[u][pre[u]]-=res[t];
flow[pre[u]][u]+=res[t];
}
ans+=res[t];
}
// cout<<ans<<endl;
}
int a[1000],b[1000];
int main()
{
while(cin>>n>>m&&n!=0)
{
clean(mp,0);
for(int i=0;i<m;++i)
{
cin>>a[i]>>b[i];
cin>>mp[a[i]][b[i]];
mp[b[i]][a[i]]=mp[a[i]][b[i]];
}
// for(int i=0;i<=n;++i)
// {
// for(int j=0;j<=n;++j)
// cout<<mp[i][j]<<" ";
// cout<<endl;
// }
s=1,t=2;
maxflow();//最大流
for(int i=0;i<m;++i)
{
if((res[a[i]]==0&&res[b[i]])
||(res[a[i]]&&res[b[i]]==0))//前后有断层
cout<<a[i]<<" "<<b[i]<<endl;
}
cout<<endl;
}
}