自学内容网 自学内容网

费用流,LeetCode 2850. 将石头分散到网格图的最少移动次数

一、题目

1、题目描述

给你一个大小为 3 * 3 ,下标从 0 开始的二维整数矩阵 grid ,分别表示每一个格子里石头的数目。网格图中总共恰好有 9 个石头,一个格子里可能会有 多个 石头。

每一次操作中,你可以将一个石头从它当前所在格子移动到一个至少有一条公共边的相邻格子。

请你返回每个格子恰好有一个石头的 最少移动次数 。

2、接口描述

cpp
 ​
class Solution {
public:
    int minimumMoves(vector<vector<int>>& grid) {
        
    }
};

3、原题链接

2850. 将石头分散到网格图的最少移动次数


二、解题报告

1、思路分析

网络流建图就完了,考虑怎么建

首先虚拟源汇点s、t

对于石头数目c大于1的格子,从源点向其连容量为 c - 1, 费用为0的边

从该格子向所有石头数目为0的格子连容量为1,费用为曼哈顿距离的边

对于所有权值为0的格子,向汇点连容量为1,费用为0的边

跑最小费用最大流就行了

2、复杂度

时间复杂度: EK算法理论时间复杂度上限为O(NM^2)空间复杂度:O(N + M)

3、代码详解

cpp
 
constexpr int N = 15, inf = 1e9;
struct edge {
    int v, c, w, nxt;
} adj[N * 12];

int s, t;
int head[N], idx;
int q[N], dst[N], incf[N], pre[N];
bool vis[N];

void init() {
    memset(head, -1, sizeof head);
    idx = 0;
    s = 0, t = 10;
}

void addedge(int u, int v, int c, int w) {
    adj[idx] = { v, c, w, head[u] }, head[u] = idx ++;
}

void add(int u, int v, int c, int w) {
    addedge(u, v, c, w), addedge(v, u, 0, -w);
}

bool spfa() {
    memset(incf, 0, sizeof incf);
    memset(dst, 0x3f, sizeof dst);
    int f = 0, b = 0;
    dst[q[b ++] = s] = 0, vis[s] = true, incf[s] = inf;
    while (b - f) {
        int u = q[f ++];
        f %= N;
        vis[u] = false;
        for (int i = head[u]; ~i; i = adj[i].nxt) {
            int v = adj[i].v;
            if (adj[i].c && dst[v] > dst[u] + adj[i].w) {
                dst[v] = dst[u] + adj[i].w;
                incf[v] = std::min(incf[u], adj[i].c);
                pre[v] = i;
                if (vis[v]) continue;
                vis[q[b ++] = v] = true;
                b %= N;
            }
        }
    }
    return incf[t];
}

void update(int& f, int& c) {
    for (int v = t; v != s; ) {
        int i = pre[v];
        adj[i].c -= incf[t];
        adj[i ^ 1].c += incf[t];
        v = adj[i ^ 1].v;
    }
    c += dst[t] * incf[t];
    f += incf[t];
}

int EK() {
    int f = 0, c = 0;
    while(spfa())
        update(f, c); 
    return c;
}

int getp(int x, int y) {
    return x * 3 + y + 1;
}

class Solution {
public:
    int minimumMoves(vector<vector<int>>& grid) {
        init();
        for (int i = 0; i < 3; ++ i) 
            for (int j = 0; j < 3; ++ j) {
                if (grid[i][j] > 1) {
                    add(s, getp(i, j), grid[i][j] - 1, 0);
                    for (int ii = 0; ii < 3; ++ ii) 
                        for (int jj = 0; jj < 3; ++ jj) 
                            if (!grid[ii][jj])
                                add(getp(i, j), getp(ii, jj), 1, abs(i - ii) + abs(j - jj));
                }
                else if(grid[i][j] == 0)
                    add(getp(i, j), t, 1, 0);
            }
                
        return EK();
    }
};


原文地址:https://blog.csdn.net/EQUINOX1/article/details/140571894

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!