2022-06-12:在N*N的正方形棋盘中,有N*N个棋子,那么每个格子正好可以拥有一个棋子。 但是现在有些棋子聚集到一个格子上了,比如: 2 0 3 0 1 0 3 0 0 如上的二维数组代表,一
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;
}
执行结果如下:

2022-06-12:在N*N的正方形棋盘中,有N*N个棋子,那么每个格子正好可以拥有一个棋子。 但是现在有些棋子聚集到一个格子上了,比如: 2 0 3 0 1 0 3 0 0 如上的二维数组代表,一的更多相关文章
- UDP通信接收端,接收二维数组,内容为0与1
1: using System; 2: using System.Net; 3: using System.Net.Sockets; 4: using System.Text; 5: 6: 7 ...
- C语言:将3*5矩阵中第k列的元素左移到第0列,第k列以后的每列元素依次左移,原来左边的各列依次绕到右边。-在m行m列的二维数组中存放如下规律的数据,
//将3*5矩阵中第k列的元素左移到第0列,第k列以后的每列元素依次左移,原来左边的各列依次绕到右边. #include <stdio.h> #define M 3 #define N 5 ...
- 程序员之--C语言细节13(二维数组和指针,&*a[i][0]的理解,数组1[e]和e[1]非常可能你没见过)
主要内容:二维数组和指针.&*a[i][0]的理解.数组1[e]和e[1] #include <stdio.h> #define NUM_ROWS 10 #define NUM_C ...
- JS数组 二维数组 二维数组的表示 方法一: myarray[ ][ ];方法二:var Myarr = [[0 , 1 , 2 ],[1 , 2 , 3, ]]
二维数组 一维数组,我们看成一组盒子,每个盒子只能放一个内容. 一维数组的表示: myarray[ ] 二维数组,我们看成一组盒子,不过每个盒子里还可以放多个盒子. 二维数组的表示: myarray[ ...
- 2017.12.10 Java写一个杨辉三角(二维数组的应用)
杨辉三角的定律 第n行m列元素通项公式为: C(n-1,m-1)=(n-1)!/[(m-1)!(n-m)!] 需要用到创建二维数组 package com.glut.demo; /** * 杨辉三角 ...
- Java知识系统回顾整理01基础06数组06二维数组
一.一维数组和二维数组 这是一个一维数组, 里面的每一个元素,都是一个基本类型int int a[] =new int[]{1,2,3,4,5}; 这是一个二维数组,里面的每一个元素,都是一个一维数组 ...
- 对一个二维数组进行升序排列a[0][1]为最小
public static int[][] dyadicArraySort(int a[][]){ int temp=0;int sum =0;int nn=0; for(int i=0;i<a ...
- yii2.0中添加二维数组,多条数据。
/** * @inheritdoc 批量添加 * @params $add array 添加数据 */public function add_all($add){ $connection = \Yii ...
- C语言基础:二维数组 分类: iOS学习 c语言基础 2015-06-10 21:42 16人阅读 评论(0) 收藏
二维数组和一位数组类似. 定义: 数据类型 数组名[行][列]={{ },{ }....}; 定义时,一维(行)的长度可以省略,但是二维(列)的长度不可以省略.但是访问时,一定使用双下标. 二维数组的 ...
- php 二维数组key初始化从0开始
这个是一个二维数组 array(2) { [1]=> array(2) { ["sourcesid"]=> int(1) ["addusernum" ...
随机推荐
- 关于proTable设置列固定,始终没有固定的效果的原因
使用proTable设置操作列固定 const columns: ProColumns<IssueItem>[] = [ { title: '操作', valueType: 'option ...
- git提交的时候,报错yarn run v1.21.1 ,SyntaxError: Cannot use import statement outside a module 解决
原因是 lint-staged这个依赖中,需要的node的版本是, 而我使用的node版本是12.13.1 ,切换成14.17.0就可以了
- sql 查询大数据 常用 50列优化
大数据量的问题是很多面试笔试中经常出现的问题,比如baidu google 腾讯 这样的一些涉及到海量数据的公司经常会问到. 下面的方法是我对海量数据的处理方法进行了一个一般性的总结,当然这些方法可能 ...
- AI来实现代码转换!Python转Java,Java转Go不在话下?
今天看到个有趣的网站,给大家分享一下. 该网站的功能很神奇,可以实现编程语言的转化.感觉在一些场景之下还是有点作用的,比如你原来跟我一样是做Java的,因为工作需要突然转Go.这个时候用你Java的经 ...
- Axios的相关应用
Axios 的案例应用 要求利用axios实现之前利用AJAX实现的验证用户是否登录的案例 鉴于这两种语法的相似性,只需要在AJAX里面的注册界面里面的script标签里面包含的代码修改为如下代码即可 ...
- Go 语言:通过TDD测试驱动开发学习 Mocking (模拟)的思想
正文: 现在需要你写一个程序,从 3 开始依次向下,当到 0 时打印 「GO!」 并退出,要求每次打印从新的一行开始且打印间隔一秒的停顿. 3 2 1 Go! 我们将通过编写一个 Co ...
- ES5新增数组常见方法(indexof/forEach/map/filter)
新增的数组常见方法:以下说明中,红色为必选参数,蓝色为可选参数 1.indexOf(data,start); 用于返回某个数组或者字符串中规定字符或者字符串的位置: var arr = [" ...
- app稳定性测试-iOS篇
稳定性测试:测试应用程序在长时间运行过程中是否存在内存泄漏.崩溃等问题,以确保应用程序具有较高的稳定性和可靠性. 对于安卓端,官方提供了很好的稳定性测试工具:monkey. 相比较而言,iOS则没有, ...
- JQuery点击复制文本框内容的方法插件
[导读] 文章介绍了两种常用的点击复制文本框内容方法,一种是but IE only,同样的这个也是我们经常使用的.优点是体积小,仅有十来行代码,但缺点也很明显,只支持IE及以IE为内核的浏览器,另一种 ...
- CommunityToolkit.Mvvm8.1 IOC依赖注入控制反转(5)
本系列文章导航 https://www.cnblogs.com/aierong/p/17300066.html https://github.com/aierong/WpfDemo (自我Demo地址 ...