Codeforces 513F1 Scaygerboss 网络流

题目链接:点击打开链接

题意:

给定n*m的地图 a个男人 b个女人

下面n*m的方格图.表示空地 *表示障碍。

下面第一行给出中性人的坐标和移动时间

下面a行给出每个男人的坐标和移动时间

下面b行给出女人的坐标和移动时间。

移动时间是指人移动到相邻矩阵的时间(人是不能走到障碍物上的)

每个空地上恰好有一间房子(一间房子只能住一对夫妇,住了人的空地别人还是可以走过的)。

目标:使得所有人都结成夫妇且住在房子里(中性人可以和男的结成夫妇,也可以和女的结成夫妇)

所花的最大时间最小,即最后一个人住进房子的时间最小。

思路:

假设没有变性人,则这题就是一个经典建图了,

二分最大时间,然后建图即可。

设now为每个人允许运动的最大时间

男人连源点 flow = 1

男人连能走到的房子 flow = 1 (所谓能走到就是所花时间<=now)

房子连女人 flow = 1

女人连汇点 flow = 1

因为一个房子只能住一个人,所以房子拆点一下,限流为1

而对于变性人其实并不是任意匹配的,当且仅当 abs(男人数量-女人数量)=1时才能找到解,即一开始就能确定变性人的性别。

f2的话一直wa87,==

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<cmath>
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if (c = getchar(), c == EOF) return 0;
	while (c != '-' && (c<'0' || c>'9')) c = getchar();
	sgn = (c == '-') ? -1 : 1;
	ret = (c == '-') ? 0 : (c - '0');
	while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
	ret *= sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x <0) {
		putchar('-');
		x = -x;
	}
	if (x>9) pt(x / 10);
	putchar(x % 10 + '0');
}
using namespace std;
typedef long long ll;
const ll inf = 1e10;
const int N = 1700;
const int M = 10000000;
template<class T>
struct Max_Flow {
	int n;
	int Q[N], sign;
	int head[N], level[N], cur[N], pre[N];
	int nxt[M], pnt[M], E;
	T cap[M];
	void Init(int n) {
		this->n = n + 1;
		E = 0;
		std::fill(head, head + this->n, -1);
	}
	//有向rw 就= 0
	void add(int from, int to, T c, T rw) {
		pnt[E] = to;
		cap[E] = c;
		nxt[E] = head[from];
		head[from] = E++;

		pnt[E] = from;
		cap[E] = rw;
		nxt[E] = head[to];
		head[to] = E++;
	}
	bool Bfs(int s, int t) {
		sign = t;
		std::fill(level, level + n, -1);
		int *front = Q, *tail = Q;
		*tail++ = t; level[t] = 0;
		while (front < tail && level[s] == -1) {
			int u = *front++;
			for (int e = head[u]; e != -1; e = nxt[e]) {
				if (cap[e ^ 1] > 0 && level[pnt[e]] < 0) {
					level[pnt[e]] = level[u] + 1;
					*tail++ = pnt[e];
				}
			}
		}
		return level[s] != -1;
	}
	void Push(int t, T &flow) {
		T mi = inf;
		int p = pre[t];
		for (int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) {
			mi = std::min(mi, cap[p]);
		}
		for (int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) {
			cap[p] -= mi;
			if (!cap[p]) {
				sign = pnt[p ^ 1];
			}
			cap[p ^ 1] += mi;
		}
		flow += mi;
	}
	void Dfs(int u, int t, T &flow) {
		if (u == t) {
			Push(t, flow);
			return;
		}
		for (int &e = cur[u]; e != -1; e = nxt[e]) {
			if (cap[e] > 0 && level[u] - 1 == level[pnt[e]]) {
				pre[pnt[e]] = e;
				Dfs(pnt[e], t, flow);
				if (level[sign] > level[u]) {
					return;
				}
				sign = t;
			}
		}
	}
	T Dinic(int s, int t) {
		pre[s] = -1;
		T flow = 0;
		while (Bfs(s, t)) {
			std::copy(head, head + n, cur);
			Dfs(s, t, flow);
		}
		return flow;
	}
};
Max_Flow <ll>F;
struct node{
	int x, y; ll t;
	node(int a = 0, int b = 0, ll c = 0) :x(a), y(b), t(c){}
}AA[N], B[N], C;
int n, m, a, b;
char mp[24][24];
ll Dis[24][24][24][24];
int has1(int x){ return x - 1; }
int has2(int x, int y){ return a + (x - 1)*m + y - 1; }
int has3(int x, int y){ return a + n*m + (x - 1)*m + y - 1; }
int has4(int x){ return a + 2 * n*m + x - 1; }
bool ok(ll now){
	int from = has4(b) + 1, to = from + 1;
	F.Init(to+10);
	for (int i = 1; i <= a; i++){
		F.add(from, has1(i), 1, 0);
		for (int x = 1; x <= n; x++)
		for (int y = 1; y <= m; y++)
			if (Dis[x][y][AA[i].x][AA[i].y] < inf && Dis[x][y][AA[i].x][AA[i].y] * AA[i].t <= now)
				F.add(has1(i), has2(x, y), 1, 0);
	}
	for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)if (mp[i][j] == '.') F.add(has2(i, j), has3(i, j), 1, 0);
	for (int i = 1; i <= b; i++){
		F.add(has4(i), to, 1, 0);
		for (int x = 1; x <= n; x++)
		for (int y = 1; y <= m; y++)
			if (Dis[x][y][B[i].x][B[i].y] < inf && Dis[x][y][B[i].x][B[i].y] * B[i].t <= now)
				F.add(has3(x, y), has4(i), 1, 0);
	}
	return F.Dinic(from, to) == b;
}
ll solve(){
	if (a != b)return -1;
	ll ans = -1, l = 0, r = 1e18;//二分答案
	while (l <= r){
		ll mid = (l + r) >> 1;
		if (ok(mid)){
			r = mid - 1;
			ans = mid;
		}
		else
			l = mid + 1;
	}
	return ans;
}
void pre(){
	for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)for (int x = 1; x <= n; x++)for (int y = 1; y <= m; y++)Dis[i][j][x][y] = inf;
	int step[4][2] = { 0, 1, 0, -1, 1, 0, -1, 0 };
	for (int i = 1; i <= n; i++)
	for (int j = 1; j <= m; j++){
		if (mp[i][j] == '*')continue;
		Dis[i][j][i][j] = 0;
		for (int k = 0; k < 4; k++){
			int x = i + step[k][0], y = j + step[k][1];
			if (1 <= x && x <= n && 1 <= y&&y <= m && mp[x][y] == '.')
				Dis[i][j][x][y] = 1;
		}
	}//Floyd
	for (int x1 = 1; x1 <= n; x1++)for (int y1 = 1; y1 <= m; y1++) if (mp[x1][y1] == '.')
	for (int x2 = 1; x2 <= n; x2++)for (int y2 = 1; y2 <= m; y2++) if (mp[x2][y2]=='.' && Dis[x2][y2][x1][y1]<inf)
	for (int x3 = 1; x3 <= n; x3++)for (int y3 = 1; y3 <= m; y3++) if (mp[x3][y3] == '.')
		Dis[x2][y2][x3][y3] = min(Dis[x2][y2][x3][y3], Dis[x2][y2][x1][y1] + Dis[x1][y1][x3][y3]);
	if (a>b)B[++b] = C; //确定变性人的性别,就相当于直接把他看成男(女)人
	else AA[++a] = C;
}
void input(){
	rd(n); rd(m); rd(a); rd(b);
	for (int i = 1; i <= n; i++)scanf("%s", mp[i] + 1);
	rd(C.x); rd(C.y); rd(C.t);
	for (int i = 1; i <= a; i++) { rd(AA[i].x); rd(AA[i].y); rd(AA[i].t); }
	for (int i = 1; i <= b; i++) { rd(B[i].x); rd(B[i].y); rd(B[i].t); }
}

int main(){
	input();
	pre();
	cout<<solve()<<endl;
	return 0;
}
/*
1 1 1 0
.
1 1 1
1 1 1

*/
时间: 2024-10-17 21:47:46

Codeforces 513F1 Scaygerboss 网络流的相关文章

网络流(最大流):CodeForces 499E Array and Operations

You have written on a piece of paper an array of n positive integers a[1], a[2], ..., a[n] and m good pairs of integers (i1, j1), (i2, j2), ..., (im, jm). Each good pair (ik, jk) meets the following conditions: ik + jk is an odd number and 1 ≤ ik < j

codeforces 510E. Fox And Dinner 网络流

题目链接 给出n个人, 以及每个人的值, 要求他们坐在一些桌子上面, 每个桌子如果有人坐, 就必须做3个人以上. 并且相邻的两个人的值加起来必须是素数.每个人的值都>=2. 由大于等于2这个条件, 可以知道素数都是奇数, 那么很明显就需要一奇一偶相邻这样做, 那么一个桌子上必定有偶数个人. 一个奇数旁边有两个偶数, 一个偶数旁边有两个奇数. 所以可以先判断n是否为偶数, 如果是奇数直接输出不可能. 然后开始奇偶建边, 源点和奇数建边, 权值为2, 因为一个奇数需要和两个偶数匹配: 偶数和汇点建边

Codeforces Gym 100203I I - I WIN 网络流最大流

I - I WINTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=87954#problem/I Description Given an n × m rectangular tile with each square marked with one of the letters W, I, and N, find the maximal numb

网络流(最大流)CodeForces 512C:Fox And Dinner

Fox Ciel is participating in a party in Prime Kingdom. There are n foxes there (include Fox Ciel). The i-th fox is ai years old. They will have dinner around some round tables. You want to distribute foxes such that: Each fox is sitting at some table

Codeforces 270E Flawed Flow 网络流问题

题意:给出一些边,给出边的容量.让你为所有边确定一个方向使得流量最大. 题目不用求最大流, 而是求每条边的流向,这题是考察网络流的基本规律. 若某图有最大,则有与源点相连的边必然都是流出的,与汇点相连的边必然是流入的,其它所有点流入和流出的流量是相等的. 我们可以根据这一规律来求解. 先求出所有点(除了源点和汇点)的总流量(表示流入的流量的2倍),每次流过该边,更新的时候减去流入流量的2倍. 从源点出发广搜每个点,搜的过程可以确定经过边的流向,当某个点的剩余总流量为0时,表示流入该点的流量边已经

codeforces gym 100357 J (网络流)

题目大意 有n种物品,m种建筑,p个人. n,m,p∈[1,20] 每种建筑需要若干个若干种物品来建造.每个人打算建造一种建筑,拥有一些物品. 主角需要通过交易来建造自己的建筑,交易的前提是对方用多余的物品来换取自己需要的物品. 询问主角是否能建造成功自己的建筑,并给出方案. 解题分析 超级恶心的读入,而且有一组数据的给出方式里没有逗号,和样例所示不同= = 根据py的性质很容易想到用网络流来做.将每种物品拆成x,y两份. 若主角多了a物品b件,连一条S到物品a,x部流量为b的边. 若主角少了a

codeforces 546E. Soldier and Traveling 网络流

题目链接 给出n个城市, 以及初始时每个城市的人数以及目标人数.初始时有些城市是相连的. 每个城市的人只可以待在自己的城市或走到与他相邻的城市, 相邻, 相当于只能走一条路. 如果目标状态不可达, 输出no, 否则输出每个城市的人都是怎么走的, 比如第一个城市有2个人走到了第二个城市, 1个人留在了第一个城市, 那么输出的第一行前两个数就是1, 2. 很明显的网络流, 输出那里写了好久... 首先判断能否可达, 如果初始状态的人数与目标状态不一样, 一定不可达, 其次, 如果建完图跑网络流的结果

codeforces 498C Array and Operations 网络流

传送门:cf 498C 给定一个长度为n的数组,已经m组下标对应关系(下标之和为奇数),现在可以对m组对应关系中的数同除一个大于1的整数,问最多能进行多少次这样的操作 要操作次数最大,每次处理的时候应该除质数. 下标之和为奇数,不难发现它构成了一张二分图. 枚举sqrt(10^9)的质数,找出n个数中各有多少个这样的质数k,然后建立对应的图,跑网络流最大流即可. /****************************************************** * File Name

Educational Codeforces Round 21 F. Card Game(网络流之最大点权独立集)

题目链接:Educational Codeforces Round 21 F. Card Game 题意: 有n个卡片,每个卡片有三个值:p,c,l; 现在让你找一个最小的L,使得满足选出来的卡片l<=L,并且所有卡片的p的和不小于k. 选择卡片时有限制,任意两张卡片的c之和不能为质数. 题解: 和hdu 1565 方格取数(2)一样,都是求最大点权独立集. 不难看出来,这题再多一个二分. 注意的是在构造二部图的时候,按照c值的奇偶性构造. 当c==1时要单独处理,因为如果有多个c==1的卡片,