SGU438 The Glorious Karlutka River =)

本文深入探讨了动态流算法的原理与应用,通过具体实例详细解析了如何使用动态流解决特定问题。文章首先介绍了动态流的基本概念,包括容量限制与时间限制下的网络构建策略,随后通过拆点和分层技巧构建复杂网络模型。通过源点和汇点的设定,以及各时刻节点间的流量控制,展示了动态流在网络流量优化中的应用。最后,提供了完整的代码实现,帮助读者理解和掌握动态流算法的实际操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

sgu原来搬到cf了呀点了好几个链接才找到233

传说中的动态流(?)

反正很暴力就对了QwQ

有容量限制->拆点 对于每个点拆成入点和出点

时间限制->分层 对于每个时刻的每个石头都建点

所以源点连最开始的到达的石头的入点 然后每个可以到达的出点连汇点

然后每个时刻的入点出点之间连接流量为C 然后可以互相跳的连inf

枚举时刻在残存网络上继续流可以了 直到一个时刻 >=m 就是所有人都跳过去了QwQ

附代码。

我觉得我这份代码巨好看(大雾)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define inf 20021225
#define ll long long
#define mxn 42010
#define mxm 960010
using namespace std;

queue<int> que;
struct point{int x,y,c;}p[51];
struct edge{int to,lt,f;}e[mxm<<1];
int in[mxn],cnt=1,dep[mxn],s,t,n,m,d,w;
void add(int x,int y,int f){e[++cnt].to=y;e[cnt].lt=in[x];e[cnt].f=f;in[x]=cnt;}
void addedge(int x,int y,int f){add(x,y,f);add(y,x,0);}
bool bfs()
{
	while(!que.empty())	que.pop();
	memset(dep,0,sizeof(dep));
	dep[s]=1;que.push(s);
	while(!que.empty())
	{
		int x=que.front();que.pop();
		for(int i=in[x];i;i=e[i].lt)
		{
			int y=e[i].to;
			if(!dep[y]&&e[i].f)
			{
				dep[y]=dep[x]+1;
				if(y==t)	return 1;
				que.push(y);
			}
		}
	}
	return 0;
}
int dfs(int x,int flow)
{
	if(x==t||!flow)	return flow;
	int cur=flow;
	for(int i=in[x];i;i=e[i].lt)
	{
		int y=e[i].to;
		if(dep[y]==dep[x]+1&&e[i].f)
		{
			int tmp=dfs(y,min(cur,e[i].f));
			cur-=tmp;e[i].f-=tmp;e[i^1].f+=tmp;
			if(!cur)	return flow;
		}
	}
	dep[x]=-1;
	return flow-cur;
}
int dinic()
{
	int ans=0;
	while(bfs())
		ans+=dfs(s,inf);
		//printf("%d\n",ans);
	return ans;
}
int id(int x,int dep){return dep*m+x;}
int dis(point a,point b){return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}
bool jump(point a,point b){return dis(a,b)<=d*d;}
bool st[51],fn[51];
int main()
{
	scanf("%d%d%d%d",&n,&m,&d,&w);
	s=mxn-4;t=s+1;
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].c);
		if(p[i].y<=d)	st[i]=1;
		if(p[i].y>=w-d)	fn[i]=1;
	}
	if(w<=d){printf("1\n");return 0;}
	int tot=0,tm;
	for(tm=0;tm<n+m;tm++)
	{
		for(int i=1;i<=n;i++)
		{
			if(st[i])	addedge(s,id(i,tm<<1),inf);
			if(fn[i])	addedge(id(i,tm<<1|1),t,inf);
			addedge(id(i,tm<<1),id(i,tm<<1|1),p[i].c);
		}
		
		tot+=dinic();
		if(tot>=m)	break;
		
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(i==j)	continue;
				if(jump(p[i],p[j]))	addedge(id(i,tm<<1|1),id(j,tm+1<<1),inf);
			}
		}
	}
	if(tm<n+m)	printf("%d\n",tm+2);
	else	printf("IMPOSSIBLE\n");
	return 0;
}

 

转载于:https://www.cnblogs.com/hanyuweining/p/10321944.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值