\(\color{#0066ff}{题目描述}\)
火星探险队的登陆舱将在火星表面着陆,登陆舱内有多部障碍物探测车。登陆舱着陆后,探测车将离开登陆舱向先期到达的传送器方向移动。探测车在移动中还必须采集岩石标本。每一块岩石标本由最先遇到它的探测车完成采集。每块岩石标本只能被采集一次。岩石标本被采集后,其他探测车可以从原来岩石标本所在处通过。探测车不能通过有障碍的地面。本题限定探测车只能从登陆处沿着向南或向东的方向朝传送器移动,而且多个探测车可以在同一时间占据同一位置。如果某个探测车在到达传送器以前不能继续前进,则该车所采集的岩石标本将全部损失。
用一个 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
给定每个位置的状态,计算探测车的最优移动方案,使到达传送器的探测车的数量最多,
而且探测车采集到的岩石标本的数量最多
\(\color{#0066ff}{输入格式}\)
第 1行为探测车数,第 2 行为 P 的值,第3 行为Q 的值。接下来的 Q 行是表示登陆舱与传送器之间的位置状态的 P·Q 网格。用 3 个数字表示火星表面位置的状态:0 表示平坦无障碍,1表示障碍,2 表示石块。
\(\color{#0066ff}{输出格式}\)
每行包含探测车号和一个移动方向,0 表示向南移动,1 表示向东移动。
\(\color{#0066ff}{输入样例}\)
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
\(\color{#0066ff}{输出样例}\)
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
\(\color{#0066ff}{数据范围与提示}\)
车数,P,Q<=35
有spj
\(\color{#0066ff}{题解}\)
拆点,跑最小费用最大流
起点跟1,1连,重点跟最后连
自己的入点出点连在一起,如果有石子,还得在连一条容量为1,边权为1的边,石子只能获得一次
对于障碍点,什么都不用连
#include <bits/stdc++.h>
#define LL long long
LL in()
{
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return x * f;
}
struct node
{
int to, dis, can;
node *nxt, *rev;
node(int to = 0, int dis = 0, int can = 0, node *nxt = NULL):to(to), dis(dis), can(can), nxt(nxt) {}
void *operator new (size_t)
{
static node *S = NULL, *T = NULL;
return (S == T) && (T = (S = new node[1024]) + 1024), S++;
}
};
const int maxn = 100050;
const int inf = 0x7fffffff;
int n, p, q, s, t;
typedef node* nod;
nod head[maxn], road[maxn];
int dis[maxn], change[maxn];
bool vis[maxn];
int id[55][55], mp[55][55];
std::queue<int> V;
void add(int from, int to, int can, int dis)
{
nod o = new node(to, dis, can, head[from]);
head[from] = o;
}
void link(int from, int to, int can, int dis)
{
add(from, to, can, dis);
add(to, from, 0, -dis);
head[from]->rev = head[to];
head[to]->rev = head[from];
}
bool bfs()
{
for(int i = s; i <= t; i++) change[i] = inf, dis[i] = -inf;
V.push(s);
dis[s] = 0;
while(!V.empty())
{
int tp = V.front(); V.pop();
vis[tp] = false;
for(nod i = head[tp]; i; i = i->nxt)
if(dis[i->to] < dis[tp] + i->dis && i->can > 0)
{
dis[i->to] = dis[tp] + i->dis;
change[i->to] = std::min(change[tp], i->can);
road[i->to] = i;
if(!vis[i->to]) vis[i->to] = true, V.push(i->to);
}
}
return change[t] != inf;
}
void mcmf()
{
while(bfs())
{
for(int o = t; o != s; o = road[o]->rev->to)
{
road[o]->can -= change[t];
road[o]->rev->can += change[t];
}
}
}
int nxt(int pos)
{
for(nod i = head[pos]; i; i = i->nxt)
if(i->to >= id[1][1] + id[p][q] && i->to <= id[p][q] + id[p][q] && i->rev->can > 0) return i->rev->can--, i->to - id[p][q];
return 0;
}
void print(int pos)
{
int now = id[1][1];
while(1)
{
int go = nxt(now);
if(go == now + 1) printf("%d 1\n", pos);
else printf("%d 0\n", pos);
now = go;
if(now == id[p][q]) break;
}
}
int main()
{
n = in(), q = in(), p = in();
for(int cnt = 0, i = 1; i <= p; i++)
for(int j = 1; j <= q; j++)
id[i][j] = ++cnt, mp[i][j] = in();
s = 0, t = (id[p][q] << 1) + 1;
link(s, id[1][1], n, 0);
link(id[p][q] << 1, t, n, 0);
for(int i = 1; i <= p; i++)
for(int j = 1; j <= q; j++)
{
if(mp[i][j] == 1) continue;
link(id[i][j] + id[p][q], id[i][j], inf, 0);
if(mp[i][j] == 2) link(id[i][j] + id[p][q], id[i][j], 1, 1);
if(i + 1 <= p)
link(id[i][j], id[i + 1][j] + id[p][q], inf, 0);
if(j + 1 <= q)
link(id[i][j], id[i][j + 1] + id[p][q], inf, 0);
}
mcmf();
for(int i = 1; i <= n; i++) print(i);
return 0;
}