1. 程式人生 > >「網路流 24 題」火星探險問題。

「網路流 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​) 處。 給定每個位置的狀態,計算探測車的最優移動方案,使到達傳送器的探測車的數量最多, 而且探測車採集到的岩石標本的數量最多。

233

輸入格式

檔案的第一行為探測車數 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;
}