网络流——刷题记录

网络流——刷题记录,第1张

网络流——刷题记录 POJ 3041 Asteroids

链接
简述:
N*N的坐标系,有K颗行星,一次可以消灭一行或者一列行星,最少需要几次?
方案:
横坐标方向和纵坐标方向的坐标为点,建立顶点两个顶点集,行星(x,y)则变成由横坐标点x指向纵坐标y的点,进行一个二分图的建立
二分图中,最小顶点覆盖等于最大匹配,因此问题可以变成一个二分图匹配问题。
最后使用网络流求解。
代码:

#include
#include
#include
#include
#include
#include
#include
#include

#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define endl "n"
#define pii pair
#define pb push_back
#define debug(x) cout << "visit:" << x << endl
#define inf 2147483647

using namespace std;

//白书的dinic板子 
struct edge
{
	int to, cap, rev;
};

const int MAX_V = 1e3+5;

vector G[MAX_V];
int level[MAX_V];
int iter[MAX_V];

void add_edge(int from,int to,int cap)
{
	G[from].push_back( (edge){to,cap,G[to].size()});
	G[to].push_back( (edge){from,0,G[from].size()-1});
}

//标记距离 
void bfs(int s)
{
	for(int i=0;i que;
	level[s] = 0;
	que.push(s);
	while(que.size()>0)
	{
		int v = que.front();
		que.pop();
		for(int i=0;i0&&level[e.to]<0)
			{
				level[e.to] = level[v]+1;
				que.push(e.to);
			}
		}
	}
}

//寻找增广路 
int dfs(int v,int t,int f)
{
	if(v==t)
	{
		return f;
	}
	for(int &i=iter[v];i0&&level[v]0)
			{
				e.cap -= d;
				G[e.to][e.rev].cap += d;
				return d;
			}
			
		}
	}
	return 0;
}

int max_flow(int s,int t)
{
	int flow = 0;
	while(1)
	{
		bfs(s);
		if(level[t]<0)//不再可达,说明已经是最大流 
		{
			return flow;
		}
		for(int i=0;i0)
		{
			flow += f;
		}
	}
}

int main()
{
	int s, t;
	int n, k;
	scanf("%d %d",&n,&k);
	s = 0;
	t = 2*n+1;
	for(int i=1;i<=n;++i)
	{
		add_edge(s,i,1);
	}
	for(int i=1;i<=n;++i)
	{
		add_edge(i+n,t,1);
	}
	for(int i=1;i<=k;++i)
	{
		int x, y;
		scanf("%d %d",&x,&y);
		add_edge(x,y+n,1);
	}
	printf("%dn",max_flow(s,t));
	return 0;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5714491.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存