UVA 11380 - Down Went The Titanic(网络流)

UVA 11380 - Down Went The Titanic

题目链接

题意:给定一个图,上面有薄冰‘.‘或‘*‘,厚冰‘@‘,木块‘#‘,一开始人都在‘*‘上,薄冰只能走一次就会沉掉,厚冰次数不限,如果人走到木块上就获救了,但是一个木块的容量只有p,求最多能有多少人获救

思路:最大流,由于点有次数限制,所以可以进行拆点,然后建图每个4和四个方向建边,源点和‘*‘建边,‘#‘和汇点建边容量为p,然后跑一下最大流即可

代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;

const int MAXNODE = 2005;
const int MAXEDGE = 100005;

typedef int Type;
const Type INF = 0x3f3f3f3f;

struct Edge {
	int u, v;
	Type cap, flow;
	Edge() {}
	Edge(int u, int v, Type cap, Type flow) {
		this->u = u;
		this->v = v;
		this->cap = cap;
		this->flow = flow;
	}
};

struct Dinic {
	int n, m, s, t;
	Edge edges[MAXEDGE];
	int first[MAXNODE];
	int next[MAXEDGE];
	bool vis[MAXNODE];
	Type d[MAXNODE];
	int cur[MAXNODE];
	vector<int> cut;

	void init(int n) {
		this->n = n;
		memset(first, -1, sizeof(first));
		m = 0;
	}
	void add_Edge(int u, int v, Type cap) {
		edges[m] = Edge(u, v, cap, 0);
		next[m] = first[u];
		first[u] = m++;
		edges[m] = Edge(v, u, 0, 0);
		next[m] = first[v];
		first[v] = m++;
	}

	bool bfs() {
		memset(vis, false, sizeof(vis));
		queue<int> Q;
		Q.push(s);
		d[s] = 0;
		vis[s] = true;
		while (!Q.empty()) {
			int u = Q.front(); Q.pop();
			for (int i = first[u]; i != -1; i = next[i]) {
				Edge& e = edges[i];
				if (!vis[e.v] && e.cap > e.flow) {
					vis[e.v] = true;
					d[e.v] = d[u] + 1;
					Q.push(e.v);
				}
			}
		}
		return vis[t];
	}

	Type dfs(int u, Type a) {
		if (u == t || a == 0) return a;
		Type flow = 0, f;
		for (int &i = cur[u]; i != -1; i = next[i]) {
			Edge& e = edges[i];
			if (d[u] + 1 == d[e.v] && (f = dfs(e.v, min(a, e.cap - e.flow))) > 0) {
				e.flow += f;
				edges[i^1].flow -= f;
				flow += f;
				a -= f;
				if (a == 0) break;
			}
		}
		return flow;
	}

	Type Maxflow(int s, int t) {
		this->s = s; this->t = t;
		Type flow = 0;
		while (bfs()) {
			for (int i = 0; i < n; i++)
				cur[i] = first[i];
			flow += dfs(s, INF);
		}
		return flow;
	}

	void MinCut() {
		cut.clear();
		for (int i = 0; i < m; i += 2) {
			if (vis[edges[i].u] && !vis[edges[i].v])
				cut.push_back(i);
		}
	}
} gao;

const int N = 35;
const int d[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};

int x, y, p;
char str[N];

int main() {
	while (~scanf("%d%d%d", &x, &y, &p)) {
		int tot = x * y;
		gao.init(2 * tot + 2);
		for (int i = 0; i < x; i++) {
			scanf("%s", str);
			for (int j = 0; j < y; j++) {
				int u = i * y + j + 1;
				if (str[j] == '*' || str[j] == '.') {
					gao.add_Edge(u, u + tot, 1);
					if (str[j] == '*')
						gao.add_Edge(0, u, 1);
				}
				if (str[j] == '#') {
					gao.add_Edge(u, u + tot, INF);
					gao.add_Edge(u + tot, 2 * tot + 1, p);
				}
				if (str[j] == '@') gao.add_Edge(u, u + tot, INF);
				for (int k = 0; k < 4; k++) {
					int xx = i + d[k][0];
					int yy = j + d[k][1];
					if (xx < 0 || xx >= x || yy < 0 || yy >= y) continue;
					int v = xx * y + yy + 1;
					gao.add_Edge(u + tot, v, INF);
				}
			}
		}
		printf("%d\n", gao.Maxflow(0, 2 * tot + 1));
	}
	return 0;
}
时间: 2024-11-05 06:05:48

UVA 11380 - Down Went The Titanic(网络流)的相关文章

UVA 10249 - The Grand Dinner(网络流 or 贪心)

UVA 10249 - The Grand Dinner 题目链接 题意:给定几队队员,几张桌子,每队有一个人数,每个桌子也有一个容量上限,要求一种安排方案,使得没有同队人坐在一个桌子上,求方案 思路:明显贪心可以搞- -, 每次往容量最多的桌子塞就可以了..不过这题既然出在网络流这章,还是用网络流也搞了下 源点连到每队,桌子连到汇点,容量就是容量,然后每队和每个桌子相连,容量为1,表示一个桌子只能做一个队员,然后跑一下最大流即可 代码: 网络流: #include <cstdio> #inc

UVA 1317 - Concert Hall Scheduling(网络流)

UVA 1317 - Concert Hall Scheduling 题目链接 题意:现在有两个音乐厅,有一些人要租用,每次租一个区间的时间,给w钱,要求一个租的方案使得总收入最大,问总收入 思路:区间k覆盖问题,一个左闭右开区间可以建一条边,容量为1,代价为-w(因为要求最大),然后区间每个[i, i + 1]建一条边,容量2,代价0,然后跑一下费用流即可 代码: #include <cstdio> #include <cstring> #include <vector&g

UVA 1306 - The K-League(网络流)

UVA 1306 - The K-League 题目链接 题意:n个球队,已经有一些胜负场,现在还有一些场次,你去分配胜负,问每支球队有没有可能获胜 思路:网络流公平分配模型,把场次当作任务,分配给人,然后先贪心,枚举每个人,让这些人能赢的都赢,剩下的去建图,每个源点连向比赛容量为场次,每个比赛连向2个球队,容量无限大,每个球队连向汇点,容量为每个的人的总和减去当前已经赢的,建完图跑一下最大流,然后判断源点流出的是否都满流即可 代码: #include <cstdio> #include &l

Uva 563 网络流

题目链接:点击打开链接 题意:给定s*a的方格点,有b个坐标是有且仅有一个人的. 每个点只能被经过一次 能不能让所有人都移动到矩阵边缘. 拆点一下,建图还是挺明显的.. 太卡了提交半天没结果,贴一下代码改天再搞好了.. //好吧1A了.. #include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<vector> using namesp

UVA 11248 - Frequency Hopping(网络流)

UVA 11248 - Frequency Hopping 题目链接 题意:给定一个网络,现在需要从1到N运输流量C,问是否可能,如果可能输出可能,如果不可能,再问是否能通过扩大一条边的容量使得可能,如果可以输出这些边(按u先排再按v排),如果不行输出不可能 思路:先做一遍网络流,然后每次在最小割上进行增加容量,需要两个优化,每次找流量找到>= c就可以了,然后每次修改容量,可以直接从之前做过的网络流继续做即可 代码: #include <cstdio> #include <cst

UVA 11765 Component Placement 网络流 新姿势建图

题目链接:点击打开链接 题意: 给定n个物品, m个约束条件 把n个物品分到2个集合里 下面第一行表示i物品分到第一个集合里的花费 第二行表示分到第二个集合里的花费 第三行表示分物品的限制(1表示只能分到第一个集合,-1表示只能分到第二个集合,0无限制) 下面m行给出约束条件 u v cost 表示u v 两点必须能互相沟通,若两点已经在同一集合则花费为0 ,若不在同一集合则花费增加cost 问满足m个约束条件下的最小花费 思路: 首先感觉是网络流,==建图比较难想 用流量表示费用 1.若i点放

UVa 11082 Matrix Decompressing (网络流)

链接:http://acm.hust.edu.cn/vjudge/problem/36866题意:对于一个R行C列的正整数矩阵(1≤R,C≤20),设Ai为前i行所有元素之和,Bi为前i列所有元素之和.已知R,C和数组A和B,找一个满足条件的矩阵.矩阵中的元素必须是1~20之间的正整数.输入保证有解.分析:这道题主要还是考查建模能力.如何把一个矩阵模型转化成网络流模型是关键之处.首先注意到矩阵任意行或列的元素之和是不变的(设第i行元素之和为Ai′,第i列元素之和为Bi′),因此想到把矩阵的每行和

UVa 11082 (网络流建模) Matrix Decompressing

网络流不难写,难的建一个能解决问题的模型.. 即使我知道这是网络流专题的题目,也绝不会能想出这种解法,=_=|| 题意: 给出一个矩阵的 前i行和 以及 前i列和,然后找到一个满足要求的矩阵,而且每个元素在1~20之间. 分析: 先求出每行的元素和A'i    每列的元素和B'i 紫书上说建一个二分图,每行是一个X节点,每列代表一个Y节点. 因为流量最小是0,而题中说元素大小在1~20之间,所以我们先将每个元素都减一. 这样每行的元素和就变成了A'i-C,每列之和变为B'i-R XY之间每条边的

【网络流#4】UVA 753 最大流

最近开始刷网络流的题目了,先从紫书上的开始,这道题是P374上的,嘛,总之这道题最终还是参考了一下紫书. 中间是用了STL中map将字符串映射成编号,使用编号总比是用字符串简单的多. 超级源点S与各个设备对应插头类型连一条边,容量为1, 超级汇点T与各个插头连一条边,容量为1 然后如果有转换器,如果x->y,那么从点x连一条容量为正无穷的边到y (因为插头同类型的有无数个) 这样跑一发最大流即可,代码中间套用模板 1 #include<cstdio> 2 #include<cstr