2022-06-12:在NN的正方形棋盘中,有NN个棋子,那么每个格子正好可以拥有一个棋子。
但是现在有些棋子聚集到一个格子上了,比如:
2 0 3
0 1 0
3 0 0
如上的二维数组代表,一共3*3个格子,
但是有些格子有2个棋子、有些有3个、有些有1个、有些没有,
请你用棋子移动的方式,让每个格子都有一个棋子,
每个棋子可以上、下、左、右移动,每移动一步算1的代价。
返回最小的代价。
来自微软。

答案2022-06-12:

km算法,距离取负数。

代码用rust编写。代码如下:

use rand::Rng;
fn main() {
let len: i32 = 4;
let test_time: i32 = 1000;
println!("测试开始");
for _ in 0..test_time {
let mut graph = random_valid_matrix(len);
let ans1 = min_distance1(&mut graph);
let ans2 = min_distance2(&mut graph);
if ans1 != ans2 {
println!("出错了!");
println!("ans1 = {}", ans1);
println!("ans2 = {}", ans2);
println!("===============");
}
}
println!("测试结束");
} // 暴力解
// 作为对数器
fn min_distance1(map: &mut Vec<Vec<i32>>) -> i32 {
let mut n = 0;
let mut m = 0;
for i in 0..map.len() as i32 {
for j in 0..map[0].len() as i32 {
n += get_max(0, map[i as usize][j as usize] - 1);
m += if map[i as usize][j as usize] == 0 {
1
} else {
0
};
}
}
if n != m || n == 0 {
return 0;
}
let mut nodes: Vec<Vec<i32>> = vec![];
for i in 0..n {
nodes.push(vec![]);
for _ in 0..2 {
nodes[i as usize].push(0);
}
}
let mut space: Vec<Vec<i32>> = vec![];
for i in 0..m {
space.push(vec![]);
for _ in 0..2 {
space[i as usize].push(0);
}
}
n = 0;
m = 0;
for i in 0..map.len() as i32 {
for j in 0..map[0].len() as i32 {
for _k in 2..map[i as usize][j as usize] {
nodes[n as usize][0] = i;
nodes[n as usize][1] = j;
n += 1;
}
if map[i as usize][j as usize] == 0 {
space[m as usize][0] = i;
space[m as usize][1] = j;
m += 1;
}
}
}
return process1(&mut nodes, 0, &mut space);
} fn process1(nodes: &mut Vec<Vec<i32>>, index: i32, space: &mut Vec<Vec<i32>>) -> i32 {
let mut ans = 0;
if index == nodes.len() as i32 {
for i in 0..nodes.len() as i32 {
ans += distance(&mut nodes[i as usize], &mut space[i as usize]);
}
} else {
ans = 2147483647;
for i in index..nodes.len() as i32 {
swap(nodes, index, i);
ans = get_min(ans, process1(nodes, index + 1, space));
swap(nodes, index, i);
}
}
return ans;
} fn swap(nodes: &mut Vec<Vec<i32>>, i: i32, j: i32) {
let tmp = nodes[i as usize].clone();
nodes[i as usize] = nodes[j as usize].clone();
nodes[j as usize] = tmp.clone();
} fn distance(a: &mut Vec<i32>, b: &mut Vec<i32>) -> i32 {
return abs(a[0] - b[0]) + abs(a[1] - b[1]);
}
fn abs(a: i32) -> i32 {
if a < 0 {
-a
} else {
a
}
} // 正式方法
// KM算法
fn min_distance2(map: &mut Vec<Vec<i32>>) -> i32 {
let mut n = 0;
let mut m = 0;
for i in 0..map.len() as i32 {
for j in 0..map[0].len() as i32 {
n += get_max(0, map[i as usize][j as usize] - 1);
m += if map[i as usize][j as usize] == 0 {
1
} else {
0
};
}
}
if n != m || n == 0 {
return 0;
}
let mut nodes: Vec<Vec<i32>> = vec![];
for i in 0..n {
nodes.push(vec![]);
for _ in 0..2 {
nodes[i as usize].push(0);
}
}
let mut space: Vec<Vec<i32>> = vec![];
for i in 0..m {
space.push(vec![]);
for _ in 0..2 {
space[i as usize].push(0);
}
}
n = 0;
m = 0;
for i in 0..map.len() as i32 {
for j in 0..map[0].len() as i32 {
for _k in 2..=map[i as usize][j as usize] {
nodes[n as usize][0] = i;
nodes[n as usize][1] = j;
n += 1;
}
if map[i as usize][j as usize] == 0 {
space[m as usize][0] = i;
space[m as usize][1] = j;
m += 1;
}
}
}
let mut graph: Vec<Vec<i32>> = vec![];
for i in 0..n {
graph.push(vec![]);
for _ in 0..n {
graph[i as usize].push(0);
}
}
for i in 0..n {
for j in 0..n {
graph[i as usize][j as usize] =
-distance(&mut nodes[i as usize], &mut space[j as usize]);
}
}
return -km(&mut graph);
} fn get_max<T: Clone + Copy + std::cmp::PartialOrd>(a: T, b: T) -> T {
if a > b {
a
} else {
b
}
} fn get_min<T: Clone + Copy + std::cmp::PartialOrd>(a: T, b: T) -> T {
if a < b {
a
} else {
b
}
} fn km(graph: &mut Vec<Vec<i32>>) -> i32 {
let nn = graph.len() as i32;
let mut match0: Vec<i32> = vec![];
let mut lx: Vec<i32> = vec![];
let mut ly: Vec<i32> = vec![];
// dfs过程中,碰过的点!
let mut x: Vec<bool> = vec![];
let mut y: Vec<bool> = vec![];
// 降低的预期!
// 公主上,打一个,降低预期的值,只维持最小!
let mut slack: Vec<i32> = vec![];
let mut falsev: Vec<bool> = vec![];
for _ in 0..nn {
match0.push(0);
lx.push(0);
ly.push(0);
x.push(false);
y.push(false);
slack.push(0);
falsev.push(false);
}
let invalid = 2147483647;
for i in 0..nn {
match0[i as usize] = -1;
lx[i as usize] = -invalid;
for j in 0..nn {
lx[i as usize] = get_max(lx[i as usize], graph[i as usize][j as usize]);
}
ly[i as usize] = 0;
}
for from in 0..nn {
for i in 0..nn {
slack[i as usize] = invalid;
}
x = falsev.clone();
y = falsev.clone();
// dfs() : from王子,能不能不降预期,匹配成功!
// 能:dfs返回true!
// 不能:dfs返回false!
while !dfs(
from,
&mut x,
&mut y,
&mut lx,
&mut ly,
&mut match0,
&mut slack,
graph,
) {
// 刚才的dfs,失败了!
// 需要拿到,公主的slack里面,预期下降幅度的最小值!
let mut d = invalid;
for i in 0..nn {
if !y[i as usize] && slack[i as usize] < d {
d = slack[i as usize];
}
}
// 按照最小预期来调整预期
for i in 0..nn {
if x[i as usize] {
lx[i as usize] = lx[i as usize] - d;
}
if y[i as usize] {
ly[i as usize] = ly[i as usize] + d;
}
}
x = falsev.clone();
y = falsev.clone();
// 然后回到while里,再次尝试
}
}
let mut ans = 0;
for i in 0..nn {
ans += lx[i as usize] + ly[i as usize];
}
return ans;
} // from, 当前的王子
// x,王子碰没碰过
// y, 公主碰没碰过
// lx,所有王子的预期
// ly, 所有公主的预期
// match,所有公主,之前的分配,之前的爷们!
// slack,连过,但没允许的公主,最小下降的幅度
// map,报价,所有王子对公主的报价
// 返回,from号王子,不降预期能不能配成!
fn dfs(
from: i32,
x: &mut Vec<bool>,
y: &mut Vec<bool>,
lx: &mut Vec<i32>,
ly: &mut Vec<i32>,
match0: &mut Vec<i32>,
slack: &mut Vec<i32>,
map: &mut Vec<Vec<i32>>,
) -> bool {
let nn = map.len() as i32;
x[from as usize] = true;
for to in 0..nn {
if !y[to as usize] {
// 只有没dfs过的公主,才会去尝试
let d = lx[from as usize] + ly[to as usize] - map[from as usize][to as usize];
if d != 0 {
// 如果当前的路不符合预期,更新公主的slack值
slack[to as usize] = get_min(slack[to as usize], d);
} else {
// 如果当前的路符合预期,尝试直接拿下,或者抢夺让之前的安排倒腾去
y[to as usize] = true;
if match0[to as usize] == -1
|| dfs(match0[to as usize], x, y, lx, ly, match0, slack, map)
{
match0[to as usize] = from;
return true;
}
}
}
}
return false;
} // 为了测试
fn random_valid_matrix(len: i32) -> Vec<Vec<i32>> {
let mut graph: Vec<Vec<i32>> = vec![];
for i in 0..len {
graph.push(vec![]);
for _ in 0..len {
graph[i as usize].push(0);
}
}
let all = len * len; for _i in 1..all {
graph[rand::thread_rng().gen_range(0, len) as usize]
[rand::thread_rng().gen_range(0, len) as usize] += 1;
}
return graph;
}

执行结果如下:


左神java代码

2022-06-12:在N*N的正方形棋盘中,有N*N个棋子,那么每个格子正好可以拥有一个棋子。 但是现在有些棋子聚集到一个格子上了,比如: 2 0 3 0 1 0 3 0 0 如上的二维数组代表,一的更多相关文章

  1. UDP通信接收端,接收二维数组,内容为0与1

    1: using System; 2: using System.Net; 3: using System.Net.Sockets; 4: using System.Text; 5:   6:   7 ...

  2. C语言:将3*5矩阵中第k列的元素左移到第0列,第k列以后的每列元素依次左移,原来左边的各列依次绕到右边。-在m行m列的二维数组中存放如下规律的数据,

    //将3*5矩阵中第k列的元素左移到第0列,第k列以后的每列元素依次左移,原来左边的各列依次绕到右边. #include <stdio.h> #define M 3 #define N 5 ...

  3. 程序员之--C语言细节13(二维数组和指针,&amp;*a[i][0]的理解,数组1[e]和e[1]非常可能你没见过)

    主要内容:二维数组和指针.&*a[i][0]的理解.数组1[e]和e[1] #include <stdio.h> #define NUM_ROWS 10 #define NUM_C ...

  4. JS数组 二维数组 二维数组的表示 方法一: myarray[ ][ ];方法二:var Myarr = [[0 , 1 , 2 ],[1 , 2 , 3, ]]

    二维数组 一维数组,我们看成一组盒子,每个盒子只能放一个内容. 一维数组的表示: myarray[ ] 二维数组,我们看成一组盒子,不过每个盒子里还可以放多个盒子. 二维数组的表示: myarray[ ...

  5. 2017.12.10 Java写一个杨辉三角(二维数组的应用)

    杨辉三角的定律 第n行m列元素通项公式为: C(n-1,m-1)=(n-1)!/[(m-1)!(n-m)!] 需要用到创建二维数组 package com.glut.demo; /** * 杨辉三角 ...

  6. Java知识系统回顾整理01基础06数组06二维数组

    一.一维数组和二维数组 这是一个一维数组, 里面的每一个元素,都是一个基本类型int int a[] =new int[]{1,2,3,4,5}; 这是一个二维数组,里面的每一个元素,都是一个一维数组 ...

  7. 对一个二维数组进行升序排列a[0][1]为最小

    public static int[][] dyadicArraySort(int a[][]){ int temp=0;int sum =0;int nn=0; for(int i=0;i<a ...

  8. yii2.0中添加二维数组,多条数据。

    /** * @inheritdoc 批量添加 * @params $add array 添加数据 */public function add_all($add){ $connection = \Yii ...

  9. C语言基础:二维数组 分类: iOS学习 c语言基础 2015-06-10 21:42 16人阅读 评论(0) 收藏

    二维数组和一位数组类似. 定义: 数据类型 数组名[行][列]={{ },{ }....}; 定义时,一维(行)的长度可以省略,但是二维(列)的长度不可以省略.但是访问时,一定使用双下标. 二维数组的 ...

  10. php 二维数组key初始化从0开始

    这个是一个二维数组 array(2) { [1]=> array(2) { ["sourcesid"]=> int(1) ["addusernum" ...

随机推荐

  1. 钉钉获取第三方token时提示签名时间戳参数超时的处理方法

    今天在更新平台功能时,碰到一个问题,从钉钉跳转到平台,始终不能成功.查看日志发现,出现了 签名时间戳参数超时 的错误. 想着没有动过相对应的代码,应该不是代码的问题. 查询官方文档,没有给出明确的答复 ...

  2. 继续Vue的探索

    接上集 上次到了想要利用Vue实现隔行变色的请求,但是由于使用的代码过于"高级"导致无法识别,这就需要利用webpack来解决它! webpack的基本使用 1.首先,在项目中安装 ...

  3. 使用containerd搭建MinIO集群服务

    概述 因为在云服务器上默认只有一块磁盘,如果直接在系统盘上安装MinIO,会被拒绝,所以这里采用containerd的方式绕过这一限制 操作环境 操作系统 CentOS 7.9 MinIO版本 REL ...

  4. 什么是mvvm?简单介绍它的概念、原理及实现

    1.MVVM的概念 model-view-viewModel,通过数据劫持+发布订阅模式来实现. mvvm是一种设计思想.Model代表数据模型,可以在model中定义数据修改和操作的业务逻辑;vie ...

  5. 从零开始学Java系列之如何使用记事本编写java程序

    前言 在上一篇文章中,壹哥给大家介绍了Java中的标识符及其命名规则.规范,Java里的关键字和保留字,以及Java中的编码规范. 我们在之前编写案例时,使用的开发工具都是windows自带的txt记 ...

  6. springboot格式化timestamp时间

    spring.jackson.date-format=yyyy-MM-dd HH:mm:ss

  7. TCC 分布式事务解决方案

    更多内容,前往 IT-BLOG 一.什么是 TCC事务 TCC 是Try.Confirm.Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作:预处理Try.确认Confirm.撤销Canc ...

  8. Rancher 系列文章-Rancher 对接 Active Directory 实战

    概述 只要是个公司,基本上都有邮箱和 AD(Active Directory). 在 AD 里,已经有了: 用户 账号密码 邮箱 用户组 组织架构 所以对于一些仅限于本公司一定范围内人员使用的管理或后 ...

  9. JS - new Function

    Function 在JavaScript当中,除了可以使用function或箭头函数定义方法外,还可以使用new Function的形式动态创建函数,此时与eval()方法类似 创建一个不接收参数的方 ...

  10. -O1 -O2 -O3 优化的原理是什么?

    一般来说,如果不指定优化标识的话,gcc就会产生可调试代码,每条指令之间将是独立的:可以在指令之间设置断点,使用gdb中的 p命令查看变量的值,改变变量的值等.并且把获取最快的编译速度作为它的目标. ...