ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

UVA12125 题解

2022-07-18 12:03:06  阅读:152  来源: 互联网

标签:ver 冰块 idx int 题解 UVA12125 depth 100


UVA12125 题解

前言

一道经典的最大流问题,考察拆点和建图技巧

思路

对于每一个冰块上企鹅的数量,我们可以从源点 \(S\) 向每一个冰块连一条容量为该冰块上企鹅数量的边。

对于每一个冰块上所限制的起跳数量,直接建图不好建,考虑拆点,对于第 \(i\) 个冰块,我们将它拆成 \(i\) 和 \(n + i\) 两个冰块,此时从 \(i\) 节点向 \(i+1\) 节点连一条容量为对应限制的起跳数量的边,这样可以保证每一个冰块实际起跳次数总是不大于最大起跳次数。

对于每一对冰块,我们判断企鹅的最长跳跃距离和这一对冰块的距离,如果前者大于后者,则这对冰块应该连边,容量是几呢?因为我们已经保证每个冰块上所限制的起跳数量了,所以这里容量直接设成 \(INF\) 即可。

因为不知道最终企鹅会聚集在哪一个点 \(T\) ,那么我们枚举 \(T\) 的位置,对于每一个位置求一遍最大流,如果合法(标准见下一段),那么记录答案。

对于每个最大流,只需判断最大流和企鹅的数量,如果相等,那么说明所有企鹅都到了 \(T\) 点,合法;否则,有一些企鹅没有到达 \(T\) 点,不合法。

注意

  • 每一行不可以有多余的行末空格。
  • 遍历 \(T\) 时,需要初始化残留网络。
  • 对于复杂度,如果仔细算一算的话时间还是挺紧的,不过网络流的复杂度就是瞎扯,很难达到理论最大值。
  • 注意点数和边数上界,点数好算 \(100\times 2 + 2\),边数需要仔细考虑,计算表达式为:\((100\times 100 + 100 \times 2)\times 2\),解释一下,最多有 \(100\) 个点,那么最多的冰块组合有 \(100\times 100\) 个,对于源点汇点最多连 \(100\) 条边,由于维护的是残留网络,正向反向边都需要,所以最后要乘 \(2\)。

Code

#include <iostream>
#include <cstring>

#define x first
#define y second

using namespace std;

typedef pair<int, int> PII;

const int N = 210, M = 20410, INF = 1e8;
const double eps = 1e-8;

int n, S, T;
double D;
int h[N], e[M], f[M], ne[M], idx;
int q[N], depth[N], cur[N];
PII p[N];

bool check(PII a, PII b)
{
	double dx = a.x - b.x;
	double dy = a.y - b.y;
	return dx * dx + dy * dy < D * D + eps * eps; //精度问题
}

void add(int a, int b, int c)
{
	e[idx] = b;
	f[idx] = c;
	ne[idx] = h[a];
	h[a] = idx ++ ;
	
	e[idx] = a;
	f[idx] = 0;
	ne[idx] = h[b];
	h[b] = idx ++ ;
	
	return;
}

bool bfs()
{
	int hh = 0, tt = 0;
	memset(depth, -1, sizeof depth);
	q[0] = S;
	depth[S] = 0;
	cur[S] = h[S];
	
	while (hh <= tt)
	{
		int t = q[hh ++ ];
		for (int i = h[t]; ~i; i = ne[i])
		{
			int ver = e[i];
			if (depth[ver] == -1 && f[i] > 0)
			{
				depth[ver] = depth[t] + 1;
				cur[ver] = h[ver];
				q[ ++ tt] = ver;
				if (ver == T) return true;
			}
		}
	}
	
	return false;
}

int dfs(int u, int lmt)
{
	if (u == T) return lmt;
	int flow = 0;
	for (int i = cur[u]; ~i && flow < lmt; i = ne[i])
	{
		cur[u] = i;
		int ver = e[i];
		if (depth[ver] == depth[u] + 1 && f[i] > 0)
		{
			int t = dfs(ver, min(f[i], lmt - flow));
			if (!t) depth[ver] = -1;
			f[i] -= t;
			f[i ^ 1] += t;
			flow += t;
		}
	}
	
	return flow;
}

int dinic()
{
	int res = 0, flow = 0;
	while (bfs())
		while (flow = dfs(S, INF))
			res += flow;
	return res;
} //一直到这里都是板子

int main()
{
	int cases;
	cin >> cases;
	while (cases -- )
	{
		memset(h, -1, sizeof h); //记着初始化h
		idx = 0;
		cin >> n >> D;
		S = 0;
		
		int tot = 0;
		for (int i = 1; i <= n; i ++ )
		{
			int x, y, a, b;
			cin >> x >> y >> a >> b;
			p[i] = {x, y};
			add(S, i, a);
			add(i, n + i, b);
			tot += a;
		}
		
		for (int i = 1; i <= n; i ++ )
			for (int j = i + 1; j <= n; j ++ )
				if (check(p[i], p[j]))
				{
					add(n + i, j, INF);
					add(n + j, i, INF);
				}
        //对应思路,代码实现
		
        bool flag = 0;
		int cnt = 0;
		for (int i = 1; i <= n; i ++ )
		{
			T = i;
			for (int j = 0; j < idx; j += 2) //枚举正向边
			{
				f[j] += f[j ^ 1]; //将正向边弄成满流
				f[j ^ 1] = 0; //反向边弄成0,初始化
			}
			
			if (dinic() == tot)
			{
                if (cnt) cout << " ";
				cout << i - 1;
				cnt ++ ;
                flag = 1;
			}
		}
		
		if(!cnt) puts("-1");
		else puts("");
	}
	
	return 0;
}

标签:ver,冰块,idx,int,题解,UVA12125,depth,100
来源: https://www.cnblogs.com/LittleMoMol-kawayi/p/solution-LuoGu-UVA12125.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有