首页 > 其他分享 >列表排序

列表排序

时间:2022-09-04 09:33:28浏览次数:75  
标签:int 交换 样例 整数 列表 操作 排序

列表排序

给定一个 $n$ 行 $m$ 列的整数列表。

列表中每一行的 $m$ 个整数都是一个 $1 \sim m$ 的排列。

现在,你可以对该列表执行以下两种操作:

  • 选择一行中的两个整数并交换它们。此操作,每行最多只能执行一次。
  • 选择列表中的两列并交换它们。此操作,最多只能执行一次。

不难发现,你最多可以进行 $n+1$ 次操作,最少可以进行 $0$ 次操作,所有操作的具体执行顺序随意。

我们的目标是,通过执行上述操作,使得最终列表中每一行的 $m$ 个整数都能按照 $1,2, \dots ,m$ 的顺序排列。

请你判断,目标是否能够达成。

输入格式

第一行包含两个整数 $n,m$。

接下来 $n$ 行,每行包含 $m$ 个整数,用来表示整数列表。保证每行的 $m$ 个整数都是一个 $1 \sim m$ 的排列。

输出格式

如果目标能够达成,则输出 YES ,否则输出 NO 。

数据范围

前 $6$ 个测试点满足 $1 \leq n,m \leq 10$。
所有测试点满足 $1 \leq n,m \leq 20$。

输入样例1:

1 2 4
2 1 3 2 4
3 1 3 4 2

输出样例1:

YES

输入样例2:

4 4
1 2 3 4
2 3 4 1
3 4 1 2
4 1 2 3

输出样例2:

NO

输入样例3:

3 6
2 1 3 4 5 6
1 2 4 3 5 6
1 2 3 4 6 5

输出样例3:

YES

 

解题思路

  当时比赛时这题想了好久,花了快半个钟才AC了。比赛时候的思路是,因为每一行中交换两个数的操作只有一次,再加上只有一次的两列互换操作,因此每一行中最多只能交换两次数字。然后又想到交换两列是对所有行都产生影响,数据范围也很小,因此想到先枚举交换哪两列,然后再判断每一行能否只用不超过一次的操作使得这行变升序序列。

  下面是y总的思路。如果只有第一种操作而没有第二种操作,意味着每行最多只交换一次,交换完后变成$1 \sim n$的排列。如何判断序列能否最多交换一次变成升序呢,将当前序列与$1 \sim n$的排列进行对比,看看有几个位置不一样。如果恰好只有两个位置不一样,那么只需要交换这两个不一样的位置就可以变成升序序列了。而如果不同的位置超过两个,因为一次交换最多改变两个位置,因此必然不能只通过一次操作变成升序序列。

  如果加上第二种操作就不好处理。但可以发现数据范围很小,第二种操作只有$C_{m}^{2} + 1$种($+1$是指不交换的情况),因此可以枚举一下第二种操作,然后用上面的方法判断每一行。列操作与每行间的操作的执行先后顺序不影响结果。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 30;
 5 
 6 int n, m;
 7 int g[N][N];
 8 
 9 bool check() {
10     for (int i = 1; i <= n; i++) {
11         int cnt = 0;
12         for (int j = 1; j <= m; j++) {
13             if (g[i][j] != j) cnt++;
14         }
15         if (cnt > 2) return false;
16     }
17     
18     return true;
19 }
20 
21 int main() {
22     scanf("%d %d", &n, &m);
23     for (int i = 1; i <= n; i++) {
24         for (int j = 1; j <= m; j++) {
25             scanf("%d", &g[i][j]);
26         }
27     }
28     
29     for (int i = 1; i <= m; i++) {
30         for (int j = 1; j <= i; j++) {  // j == i 表示不交换两列的情况
31             for (int k = 1; k <= n; k++) {
32                 swap(g[k][i], g[k][j]);
33             }
34             if (check()) {
35                 printf("YES");
36                 return 0;
37             }
38             for (int k = 1; k <= n; k++) {
39                 swap(g[k][i], g[k][j]);
40             }
41         }
42     }
43     
44     printf("NO");
45     
46     return 0;
47 }

 

参考资料

  AcWing 4610. 列表排序(AcWing杯 - 周赛):https://www.acwing.com/video/4298/

标签:int,交换,样例,整数,列表,操作,排序
From: https://www.cnblogs.com/onlyblues/p/16654270.html

相关文章

  • leetcode 面试题08.08 有重复字符串的排列组合 C/C++ 排序 + 深度优先搜索(分支限界)
    #include<iostream>#include<algorithm>#include<vector>usingnamespacestd;classSolution{public:vector<string>permutation(stringS){sort(S.begin(......
  • 归并排序
    需要额外空间的外部排序?菜鸟教程版本这个版本的写法很不一样,首先,它每次都copy构造了两个子数组,然后再从这两个子数组中挑元素往原数组放构造的两个子数组容量都+1,并且......
  • 基于koa模块和socket.io模块搭建的node服务器实现通过jwt 验证来渲染列表、私聊、群聊
    1.具体代码在需要的下载https://gitee.com/zyqwasd/socket      效果: 2.package.json文件1.下载基本的模块 修改了start脚本 nodemon需要先单独......
  • 排序
    其实排序能用的上的就三个:快排,归并,基排(\(O(wys)\))。(其实priority_queue可能也算)快排很好说,sort就行。还有一个stable_sort是相同大小元素顺序不变的稳定排序算法。(事实上......
  • 自定义控件——改造已有的控件——不滚动的列表视图
    不滚动的列表视图   把ListView放入ScrollView会产生问题,因为ScrollView和ListView都允许滚动,那么在双方的重叠区域,上下滑动的手势究竟表示要滚动哪个视图?Android......
  • js 实现快速排序
    //快速排序//稳定性//快速排序是以两个游标(指针)双向遍历,当两个指针相遇则遍历结束,并将相遇位置与基准值进行交换,递归出口为左游标>=右游标//快速排序的每一轮处理......
  • 饮冰三年-人工智能-Pandas-78-Pandas 新增、统计、排序
    上一篇:饮冰三年-人工智能-Pandas-77-Pandas数据查询 数据准备可参考:饮冰三年-人工智能-Django淘宝拾遗-75-数据准备一、新增数据列1.1直接赋值#1:直接赋值(将性别......
  • 信息学奥赛一本通 1185:单词排序
    时间限制:1000ms      内存限制:65536KB提交数:20423   通过数:10401【题目描述】输入一行单词序列,相邻单词之间由1个或多个空格间隔,请按照字典......
  • 排序算法整理(包括初赛)
    排序算法整理常见考点将一个乱掉的字符串排回有序(以交换为基本操作)的最少操作,就是冒泡排序。排序算法的稳定性排序算法的时间复杂度排序算法的稳定性稳定性是指排......
  • 信息学奥赛 1181:整数奇偶排序
    时间限制:1000ms      内存限制:65536KB提交数:23930   通过数:15560【题目描述】给定10个整数的序列,要求对其重新排序。排序要求:1.奇数在前,偶......