1. 程式人生 > >最小割點【洛谷P1345】

最小割點【洛谷P1345】

傳送門:https://www.luogu.org/problemnew/show/P1345

最小割問題,大家應該聽說過,最大流最小割吧(沒聽說過的讀完這句話應該聽說了),既然要求最小割,那麼我們就直接dinic跑一下最大流就完事了。

有人要問了,你說的輕巧,我寫了dinic怎麼WA了???

這個題是最小割【點】啊!

平常的dinic跑最大流求最小割那割的是邊。

:那怎麼割點啊,看起來很困難啊好像。

觀察一下這個網路流,有1~n個點,有m條邊。

既然題目要我割點,那麼我們就把點拆成邊就好啦。

我們把點i連在i+n上,我們就把點拆成了邊,而且邊權是1,那麼這個邊割掉了,就相當於這個點割掉了。

其餘的正常的邊設定成INF吧。

下面是我優美的dinic模板,(只寫了當前弧優化,沒寫炸點優化)

PS:跑dinic的時候傳參傳了(c1,c2),WA翻天,百思不得其解,突然靈機一動,我點都拆開了,我在幹嘛???

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1010;
const int INF = 1e9+7;
int n,m,c1,c2;
struct edge
{
	int to;
	int cap;
	int rev;
};
vector<edge> G[maxn];
int depth[maxn],arc[maxn];
void add_edge(int from,int to,int cost)
{
	G[from].push_back((edge){to,cost,G[to].size()});
	G[to].push_back((edge){from,0,G[from].size()-1});
}
void bfs(int s)
{
	queue<int> q;
	memset(depth,-1,sizeof(depth));
	depth[s] = 0;
	q.push(s);
	while(!q.empty())
	{
		int v = q.front();
		q.pop();
		for(int i=0;i<G[v].size();i++)
		{
			edge &e = G[v][i];
			if(e.cap>0 && depth[e.to]<0)
			{
				depth[e.to] = depth[v]+1;
				q.push(e.to);
			}
		}
	}
}
int dfs(int v,int t,int f)
{
	if(v==t) return f;
	for(int &i=arc[v];i<G[v].size();i++)
	{
		edge &e = G[v][i];
		if(e.cap>0 && depth[e.to]==depth[v]+1)
		{
			int d = dfs(e.to,t,min(f,e.cap));
			if(d>0)
			{
				e.cap -= d;
				G[e.to][e.rev].cap += d;
				return d;
			}
		}
	}
	return 0;
}
int dinic(int s,int t)
{
	int flow = 0;
	while(true)
	{
		bfs(s);
		if(depth[t]<0) return flow;
		memset(arc,0,sizeof(arc));
		int f;
		while((f=dfs(s,t,INF))>0)
		{
			flow += f;
		}
	}
} 
int main()
{
	cin>>n>>m>>c1>>c2;
	for(int i=1;i<=n;i++)
	{
		add_edge(i,i+n,1);
	}
	for(int i=0;i<m;i++)
	{
		int x,y;
		cin>>x>>y;
		add_edge(x+n,y,INF);
		add_edge(y+n,x,INF);
	}
	cout<<dinic(c1+n,c2)<<endl;
	return 0;
}