UVA -10480 -Sabotage (无向图最小割,输出割边,dinic+向前星)

题目链接: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;
	}
}

猜你喜欢

转载自blog.csdn.net/qq_40482358/article/details/81939550