「網路流 24 題」火星探險問題。
#6225. 「網路流 24 題」火星探險問題
記憶體限制:256 MiB 時間限制:1000 ms 標準輸入輸出
題目型別:傳統 評測方式:Special Judge
上傳者: 匿名
題目描述
火星探險隊的登陸艙將在火星表面著陸,登陸艙內有多部障礙物探測車。
登陸艙著陸後,探測車將離開登陸艙向先期到達的傳送器方向移動。
探測車在移動中還必須採集岩石標本。
每一塊岩石標本由最先遇到它的探測車完成採集。
每塊岩石標本只能被採集一次。
岩石標本被採集後,其他探測車可以從原來岩石標本所在處通過。
探測車不能通過有障礙的地面。
本題限定探測車只能從登陸處沿著向南或向東的方向朝傳送器移動,而且多個探測車可以在同一時間佔據同一位置。
如果某個探測車在到達傳送器以前不能繼續前進,則該車所採集的岩石標本將全部損失。
用一個 P×Q\text{P}\times \text{Q}P×Q 網格表示登陸艙與傳送器之間的位置。登陸艙的位置在 (X1,Y1)(X_1,Y_1)(X1,Y1) 處,傳送器 的位置在 (XP,YQ)(X_P,Y_Q)(XP,YQ) 處。 給定每個位置的狀態,計算探測車的最優移動方案,使到達傳送器的探測車的數量最多, 而且探測車採集到的岩石標本的數量最多。
輸入格式
檔案的第一行為探測車數 car\text{car}car ,第二行為 P\text{P}P 的值,第三行為 Q\text{Q}Q 的值。
接下來的 Q\text{Q}Q 行是表示登陸艙與傳送器之間的位置狀態的 P×Q\text{P}\times \text{Q}P×Q 網格。
用三個數字表示火星表面位置的狀態:0
表示平坦無障礙,1
表示障礙,2
表示石塊。
輸出格式
程式執行結束時,輸出每個探測車向傳送器移動的序列。
每行包含探測車號和一個移動方向,0
表示向南移動,1
表示向東移動。
資料範圍與提示
1≤P,Q,car≤351\leq P,Q,\text{car}\leq 351≤P,Q,car≤35
題解:每個礦石只能撿一次,可以把這個點拆成兩個點(入點,出點),兩點連一條容量為1,費用為1的邊。沒障礙的點拆成兩點,連線一條費用為0,流量為inf的邊。 s與(1,1),(n,m)與t連一條費用為0,流量為car的邊 跑最大流最大費用即可。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define oo cout<<"!!!"<<endl;
typedef long long ll;
typedef unsigned long long ull;
#define ms(s) memset(s, 0, sizeof(s))
const int inf = 0x3f3f3f3f;
//head
const int maxn = 1e6+11;
int ver[maxn],edge[maxn],cost[maxn],nxt[maxn],head[maxn],tot;
int _edge[maxn];
int mk[44][44],mp[44][43];
int d[maxn],incf[maxn],pre[maxn],v[maxn];
int n,m,s,t,ans,maxflow;
void add(int x,int y,int z,int c)
{
ver[++tot] = y, edge[tot] = z;cost[tot] = c; nxt[tot] = head[x];head[x] = tot;
ver[++tot] = x; edge[tot] = 0;cost[tot] = -c;nxt[tot] = head[y];head[y] = tot;
}
inline bool check(int x,int y) {return x<=n && x>=1 && y<=m &&y>=1 && mk[x][y]!=1;}
bool spfa()
{
queue<int>q;
memset(d,0xcf,sizeof d);
ms(v);
q.push(s);d[s] = 0;v[s] = 1;
incf[s] = inf;
while(q.size())
{
int x = q.front();q.pop();v[x] = 0;
for(int i = head[x];i;i=nxt[i])
{
if(!edge[i])continue;
int y = ver[i];
if(d[y] < d[x] + cost[i])
{
d[y] = d[x] + cost[i];
incf[y] = min(incf[x],edge[i]);
pre[y] = i;
if(!v[y])q.push(y),v[y] = 1;
}
}
}
if(d[t] == 0xcfcfcfcf)return false;
return true;
}
void update()
{
int x = t;
while(x != s)
{
int i = pre[x];
edge[i] -= incf[t];
edge[i^1] += incf[t];
x = ver[i^1];
}
maxflow += incf[t];
ans += d[t] * incf[t];
}
bool print(int num,int x)
{
if(x == mp[n][m])return true;
for(int i = head[x];i;i = nxt[i])
{
if(edge[i^1] && (i&1^1))
{
edge[i^1]--;
if(ver[i] <= n*m)printf("%d %d\n",num,ver[i] == x+1-n*m);
if (print(num,ver[i])) return true;
}
}
return false;
}
int main()
{
tot = 1;
int cnt = 0;
int k;
cin>>k>>m>>n;
rep(i,1,n+1)
rep(j,1,m+1)
{
scanf("%d",&mk[i][j]);
mp[i][j] = ++cnt;
}
s = n*m*2+1; t = s+1;
add(s,mp[1][1],k,0);
add(mp[n][m]+n*m,t,k,0);
rep(i,1,n+1)
rep(j,1,m+1)
{
if(mk[i][j] == 1)continue;
if(mk[i][j] == 2)add(mp[i][j],mp[i][j]+n*m,1,1);
add(mp[i][j],mp[i][j]+n*m,inf,0);
if(check(i+1,j)) add(mp[i][j]+n*m,mp[i+1][j],inf,0);
if(check(i,j+1)) add(mp[i][j]+n*m,mp[i][j+1],inf,0);
}
while(spfa())update();
rep(i,1,k+1)
print(i,mp[1][1]);
return 0;
}