生活随笔
收集整理的這篇文章主要介紹了
网络流24题23. 火星探险问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
火星探險問題
Description
火星探險隊的登陸艙將在火星表面著陸,登陸艙內有多部障礙物探測車。登陸艙著陸后,探測車將離開登陸艙向先期到達的傳送器方向移動。探測車在移動中還必須采集巖石標本。每一塊巖石標本由最先遇到它的探測車完成采集。每塊巖石標本只能被采集一次。巖石標本被采集后,其他探測車可以從原來巖石標本所在處通過。探測車不能通過有障礙的地面。本題限定探測車只能從登陸處沿著向南或向東的方向朝傳送器移動,而且多個探測車可以在同一時間占據同一位置。如果某個探測車在到達傳送器以前不能繼續前進,則該車所采集的巖石標本將全部損失。
用一個 P×Q 網格表示登陸艙與傳送器之間的位置。登陸艙的位置在(X 1 ,Y 1 )處,傳送器的位置在(X P ,Y Q )處。
給定每個位置的狀態,計算探測車的最優移動方案,使到達傳送器的探測車的數量最多,而且探測車采集到的巖石標本的數量最多。
第 1 行為探測車數,第 2 行為 P 的值,第 3 行為 Q 的值。接下來的 Q 行是表示登陸艙與傳送器之間的位置狀態的 P×Q 網格。用 3 個數字表示火星表面位置的狀態:0 表示平坦無障礙,1 表示障礙,2 表示石塊。
Output
輸出每個探測車向傳送器移動的序列。
每行包含探測車號和一個移動方向,0 表示向南移動,1 表示向東移動。
題解
還是由于spj問題,將輸出進行改動,輸出能到達傳送器的車的數量以及能采集到的巖石的數量。
建立附加源S和附加匯T,建圖:
每個位置點拆成兩個,u.a和u.b。
1.S向(1,1).a連一條容量為車數,費用為0的邊。
2.(P,Q).b向T連一條容量為車數,費用為0的邊。
3.不是障礙的點u,u.a向u.b連一條容量為無窮大,費用為0的邊。
4.是石塊的點v,v.a向v.b連一條容量為1,費用為1的邊。
5.u東方或南方的點是v,u.b向v.a連一條容量為無窮大,費用為0的邊。
輸出最大流和最大費用即可。
每條ST滿流路徑都是一個探測車的路徑。
using namespace std;const
int N =
5000 +
10, M =
1000000 +
10, K =
40, inf =
0x3f3f3f3f;
struct Edge{
int fr, to, cap, flow, cost;
}edg[M];
int hd[N], nxt[M], tot;
int s, t;
int d[N], a[N], p[N],
q[N], in
q[N];
int n, P, Q;
int mp[K][K];void insert(
int u,
int v,
int w,
int x){edg[tot].fr = u, edg[tot].to = v, edg[tot].cap = w, edg[tot].cost =
x;nxt[tot] = hd[u]; hd[u] = tot;tot++;edg[tot].fr = v, edg[tot].to = u, edg[tot].cost = -
x;nxt[tot] = hd[v]; hd[v] = tot;tot++;
}
bool spfa(
int &fl,
int &cst){
for(
int i =
s; i <= t; i++) d[i] = -inf;d[
s] =
0; a[
s] = inf; p[
s] =
0;
int head =
0, tail =
1;
q[0] =
s; in
q[s] =
1;
while(head != tail){
int u =
q[head++];
if(head ==
5001) head =
0;in
q[u] =
0;
for(
int i = hd[u]; i >=
0; i = nxt[i]){Edge &e = edg[i];
if(d[e.to] < d[u] + e.cost && e.cap > e.flow){d[e.to] = d[u] + e.cost;p[e.to] = i;a[e.to] = min(a[u], e.cap - e.flow);
if(!in
q[e.to]){
q[tail++] = e.to;
if(tail ==
5001) tail =
0;in
q[e.to] =
1;}}}}
if(d[t] == -inf)
return false;fl += a[t];cst += a[t] * d[t];
int u = t;
while(u !=
s){edg[p[u]].flow += a[t];edg[p[u]^
1].flow -= a[t];u = edg[p[u]].fr;}
return true;
}
void init(){scanf(
"%d%d%d", &n, &Q, &P);
for(
int i =
1; i <= P; i++)
for(
int j =
1; j <= Q; j++)scanf(
"%d", &mp[i][j]);
}
int get(
int x,
int y,
int z){
return (
x -
1) * Q +
y + z * (P * Q);
}
void build(){memset(hd, -
1, sizeof(hd));
s =
0, t = P * Q *
2 +
1;
for(
int i =
1; i <= P; i++)
for(
int j =
1; j <= Q; j++){
if(mp[i][j] !=
1) insert(get(i, j,
0), get(i, j,
1), inf,
0);
if(mp[i][j] ==
2) insert(get(i, j,
0), get(i, j,
1),
1,
1);
if(i < P) insert(get(i, j,
1), get(i+
1, j,
0), inf,
0);
if(j < Q) insert(get(i, j,
1), get(i, j+
1,
0), inf,
0);}insert(
s, get(
1,
1,
0), n,
0);insert(get(P, Q,
1), t, n,
0);
}
void work(){build();
int flow =
0, cost =
0;
while(spfa(flow, cost));
printf(
"%d %d\n", flow, cost);
}
int main(){freopen(
"prog823.in",
"r", stdin);freopen(
"prog823.out",
"w", stdout);init();work();
return 0;
}
總結
以上是生活随笔為你收集整理的网络流24题23. 火星探险问题的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。