费用流,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();
    }
};

相关推荐

  1. 网格bfs,LeetCode 2684. 矩阵中移动最大次数

    2024-07-22 00:02:03       37 阅读
  2. leetcode2684--矩阵中移动最大次数

    2024-07-22 00:02:03       38 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-22 00:02:03       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-22 00:02:03       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-22 00:02:03       45 阅读
  4. Python语言-面向对象

    2024-07-22 00:02:03       55 阅读

热门阅读

  1. AQS源码

    2024-07-22 00:02:03       18 阅读
  2. 嵌入式软件工作能力

    2024-07-22 00:02:03       16 阅读
  3. C#各种锁知识点

    2024-07-22 00:02:03       17 阅读
  4. Python之后端Django(四)

    2024-07-22 00:02:03       17 阅读
  5. n4.Nginx 核心模块

    2024-07-22 00:02:03       14 阅读
  6. android audio 相机按键音:(二)加载与修改

    2024-07-22 00:02:03       20 阅读
  7. 数字转换(树形DP)

    2024-07-22 00:02:03       18 阅读
  8. python 爬虫技术 第03节 基础复习 控制结构

    2024-07-22 00:02:03       17 阅读