洛谷P3356 火星探险问题
? 解题记录 ? ? 洛谷 ? ? 费用流 ? ? 网络流 ?    2018-01-27 23:29:45    405    0    0

题目描述

火星探险队的登陆舱将在火星表面着陆,登陆舱内有多部障碍物探测车。登陆舱着陆后,探测车将离开登陆舱向先期到达的传送器方向移动。探测车在移动中还必须采集岩石标本。每一块岩石标本由最先遇到它的探测车完成采集。每块岩石标本只能被采集一次。岩石标本被采集后,其他探测车可以从原来岩石标本所在处通过。探测车不能通过有障碍的地面。本题限定探测车只能从登陆处沿着向南或向东的方向朝传送器移动,而且多个探测车可以在同一时间占据同一位置。如果某个探测车在到达传送器以前不能继续前进,则该车所采集的岩石标本将全部损失。

用一个 P·Q 网格表示登陆舱与传送器之间的位置。登陆舱的位置在(X1,Y1)处,传送器

的位置在(XP ,YQ)处。

X 1,Y 1 X 2 , Y 1 X 3 , Y 1 ... X P-1, Y 1 X P , Y 1

X 1,Y 2 X 2 , Y 2 X 3 , Y 2 ... X P-1, Y 2 X P , Y 2

X 1, Y 3 X 2 , Y 3 X 3 ,Y 3 ... X P-1, Y 3 X P , Y 3

... ...

X 1 ,Y Q-1 X 2 , Y Q-1 X 3 , Y Q-1 ... X P-1, Y Q-1 X P , Y Q-1

X 1,Y Q X 2 , Y Q X 3 , Y Q ... X P-1, Y Q X P ,Y Q

给定每个位置的状态,计算探测车的最优移动方案,使到达传送器的探测车的数量最多,

而且探测车采集到的岩石标本的数量最多

输入输出格式

输入格式:

 

第 1行为探测车数,第 2 行为 P 的值,第3 行为Q 的值。接下来的 Q 行是表示登陆舱与传送器之间的位置状态的 P·Q 网格。用 3 个数字表示火星表面位置的状态:0 表示平坦无障碍,1表示障碍,2 表示石块。

 

输出格式:

 

每行包含探测车号和一个移动方向,0 表示向南移动,1 表示向东移动。

 

输入输出样例

输入样例#1: 复制
2
10
8
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 1 0 0 0
0 0 0 1 0 2 0 0 0 0
1 1 0 1 2 0 0 0 0 1
0 1 0 0 2 0 1 1 0 0
0 1 0 1 0 0 1 1 0 0
0 1 2 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0
输出样例#1: 复制
1 1
1 1
1 1
1 1
1 0
1 0
1 1
1 1
1 1
1 1
1 0
1 0
1 1
1 0
1 0
1 0
2 1
2 1
2 1
2 1
2 0
2 0
2 0
2 0
2 1
2 0
2 0
2 1
2 0
2 1
2 1
2 1

说明

车数,P,Q<=35

考虑和方格取数一样,我们把一个方格下点拆成两个点。对于非障碍点,中间连一条费用为0流量为INF的边(可以走这里过但是不取走东西)。对于有石子的点,我们再连一条费用为1流量为1的边(只能取走一次)。注意费用流不能叠加,有石子的点既有非障碍点的连边又有自己的连边。把起点中间那条边的流量设为星球车的台数,跑最大费用流即可。

对于输出方案,我们记录每一个方格下点对应的中间边的反向边(快速获得该边增流的流量)。每一次在方格图上DFS,如果该点还有增流流量我们就走上去并且把该点增流流量减一。走K次就好了。

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxm = 100005, maxn = 105, maxp = maxn * maxn;
const int IN = 0, OUT = 1, inf = 0x3f3f3f3f;
int n, m, k;
struct edge {
	int v, cost, w, next;
}e[maxm << 1];
int head[maxp], cnt, pos[maxn][maxn][2], mp[maxn][maxn], pcnt;
int st, ed, nxt[maxn][maxn][2], flow[maxn][maxn];

void adde(const int &u, const int &v, const int &w, const int &cost) {
	e[++cnt] = (edge) {v, cost, w, head[u]};
	head[u] = cnt;
	e[++cnt] = (edge) {u, -cost, 0, head[v]};
	head[v] = cnt;
}

int dis[maxp], vis[maxp], fa[maxp], eid[maxp], ans;
void SPFA(int s, int t) {
	queue<int > q;
	for(register int i = 0; i <= pcnt; ++i) dis[i] = -inf;
	memset(vis, 0, sizeof(vis));
	memset(fa, 0, sizeof(fa));
	q.push(s), dis[s] = 0, vis[s] = 1;
	while(!q.empty()) {
		int u = q.front();
		q.pop(), vis[u] = 0;
		for(register int i = head[u]; i; i = e[i].next) {
			if(!e[i].w) continue;
			int v = e[i].v;
			if(dis[v] < dis[u] + e[i].cost) {
				dis[v] = dis[u] + e[i].cost;
				fa[v] = u, eid[v] = i;
				if(vis[v]) continue;
				q.push(v), vis[v] = 1;
			}
		}
	}
}

void ExtFlow(int s, int v, int & mn) {
	if(v == s) return;
	mn = min(e[eid[v]].w, mn);
	ExtFlow(s, fa[v], mn);
	e[eid[v]].w -= mn;
	e[eid[v] ^ 1].w += mn;
	ans += e[eid[v]].cost * mn;
}

int GetAns(int s, int t) {
	int mn = inf;
	while(1) {
		SPFA(s, t);
		if(dis[t] == -inf) break;
		mn = inf, ExtFlow(s, t, mn);
	}
	return ans;
}

void print(int x, int y, int id) {
	--flow[x][y];
	if(x + 1 <= n && flow[x + 1][y]) printf("%d %d\n", id, 0), print(x + 1, y, id);
	else if(y + 1 <= m && flow[x][y + 1]) printf("%d %d\n", id, 1), print(x, y + 1, id);
}

int main() {
	scanf("%d%d%d", &k, &m, &n);
	cnt = 1;
	for(register int i = 1; i <= n; ++i)
		for(register int j = 1; j <= m; ++j) {
			scanf("%d", &mp[i][j]);
			pos[i][j][IN] = ++pcnt; 
			pos[i][j][OUT] = ++pcnt;
			if(i == 1 && j == 1) continue;
			if(mp[i][j] == 1) continue;
			adde(pos[i][j][IN], pos[i][j][OUT], inf, 0), nxt[i][j][0] = cnt;
			if(mp[i][j] == 2) 
				adde(pos[i][j][IN], pos[i][j][OUT], 1, 1), nxt[i][j][1] = cnt;
		}
	for(register int i = 1; i < m; ++i) adde(pos[n][i][OUT], pos[n][i + 1][IN], inf, 0);
	for(register int i = 1; i < n; ++i) adde(pos[i][m][OUT], pos[i + 1][m][IN], inf, 0);
	for(register int i = 1; i < n; ++i)
		for(register int j = 1; j < m; ++j) {
			adde(pos[i][j][OUT], pos[i + 1][j][IN], inf, 0);
			adde(pos[i][j][OUT], pos[i][j + 1][IN], inf, 0);
		}
	if(mp[1][1] == 2) adde(pos[1][1][IN], pos[1][1][OUT], k - 1, 0), adde(pos[1][1][IN], pos[1][1][OUT], 1, 1);
	else adde(pos[1][1][IN], pos[1][1][OUT], k, 0);
	st = pos[1][1][IN], ed = pos[n][m][OUT];
	GetAns(st, ed);
	for(register int i = 1; i <= n; ++i)
		for(register int j = 1; j <= m; ++j) 
			flow[i][j] = e[nxt[i][j][0]].w + e[nxt[i][j][1]].w;
	for(register int i = 1; i <= k; ++i) 
		print(1, 1, i);
	return 0;
}

 

上一篇: 洛谷P2045 方格取数加强版

下一篇: 洛谷P3376 【模板】网络最大流

405 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航