PAT甲级1067. Sort with Swap(0,*) (25)

本文探讨了一种特殊情况下的序列排序问题:仅允许使用Swap(0, *)操作来对{0,1,2,...,N-1}

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given any permutation of the numbers {0, 1, 2,…, N-1}, it is easy to sort them in increasing order. But what if Swap(0, *) is the ONLY operation that is allowed to use? For example, to sort {4, 0, 2, 1, 3} we may apply the swap operations in the following way:
Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}
Now you are asked to find the minimum number of swaps need to sort the given permutation of the first N nonnegative integers.
Input Specification:
Each input file contains one test case, which gives a positive N (<=105) followed by a permutation sequence of {0, 1, …, N-1}. All the numbers in a line are separated by a space.
Output Specification:
For each case, simply print in a line the minimum number of swaps need to sort the given permutation.
Sample Input:
10 3 5 7 2 6 4 9 0 8 1
Sample Output:
9

将各个数存入数组P[];
如果0在pos处(pos!=0),即P[pos]=0,就交换0和pos,如题目所给测试用例,第一步0和7交换,这样7就归位了,然后0到了pos=2处,再交换0和2;
如果在交换过程中,0到了pos=0怎么办呢?就让0和随便什么还没有归位的数交换,这样又可以继续执行之前描述的过程。

Customized Test Case
Input
4 0 1 3 2
Output
3

#include <cstdio>
using namespace std;
#include <vector>
#include <algorithm>
#include <map>

const int MAX=100000+10;
int P[MAX];
map<int,int> M; //first:数字; second:在P数组中的下标

int main(){
  int N;
  scanf("%d",&N);

  int pos0=-1;//0的位置
  int count=0;//已经在正确位置上的数字。0不算
  int num=0;//交换的次数
  for(int i=0;i<N;i++) {
    scanf("%d",&P[i]);
    if(P[i]==i) {
      if(P[i]!=0) count++;
    }
    else{
      if(P[i]!=0) M[P[i]]=i;
    }
    if(P[i]==0) pos0=i;
  }

  int tmp;
  while(count<N-1){
  //  printf("pos0=%d\n",pos0);
    if(pos0!=0) {
      count++;
      num++;
      tmp=M[pos0];
      M.erase(pos0);
    //  printf("swap1 %d %d\n",P[pos0],P[tmp]);
      swap(P[tmp],P[pos0]);
      pos0=tmp;
    }
    else{
        num++;
        map<int,int>::iterator it=M.begin();
        tmp=it->second;
    //    printf("%d %d\n",it->first,it->second);
        M[it->first]=pos0;
      //  printf("swap2 %d %d\n",P[pos0],P[tmp]);
        swap(P[pos0],P[tmp]);
        pos0=tmp;
    }
  }

  printf("%d",num);

  return 0;
}
<think>首先,用户的问题是关于使用sed命令在包含&#39;swap&#39;的行前添加#注释。用户说:"我想注释掉包含&#39;swap&#39;的行 请问使用sed命令在包含&#39;swap&#39;的行前添加#注释"。 我需要根据系统级指令来构建我的回答: 1. **行内数学表达式**:必须使用$...$格式。但在这个问题中,没有数学表达式,所以可能不需要。用户的问题是关于sed命令的,没有涉及数学。 2. **独立公式**:必须使用$$...$$格式并单独成段。同样,这里没有公式。 3. **LaTeX语法正确**:确保任何数学表达式的LaTeX正确。 4. **使用中文回答**:整个回答必须用中文。 5. **生成相关问题**:在回答结束时,生成相关问题。 6. **引用标识**:在回答中引用的段落末尾自然地添加引用标识,例如[^1]。用户提供了几个引用: - 引用[1]: 关于sed命令注释行的例子。 - 引用[2]: 关闭swap分区的命令。 - 引用[3]: sed的i与r的使用注意。 这些引用是关于sed命令的,我应该参考它们,因为它们与用户问题相关。用户说:"上述引用仅供参考",但我应该尽可能参考用户的问题和我的回答。 用户的问题核心是:使用sed命令在包含&#39;swap&#39;的行前添加#注释。 从引用中,我可以提取有用的信息: - 引用[1]:`sed -n &#39;s/.*swap.*/#&/&#39; /etc/fstab`,其中&代表匹配到的内容。 - 引用[2]:`sed -i &#39;/ swap / s/^/# /g&#39; /etc/fstab` 和 `sed -i &#39;/ swap / s/^\(.*\)$/#\1/g&#39; /etc/fstab`。 - 引用[3]:讨论了sed的选项如-i和-r。 所以,我应该基于这些提供解决方案。 回答结构:需要结构清晰,帮助用户逐步解决问题。确保回答真实可靠。 步骤: 1. **理解需求**:用户想注释掉包含&#39;swap&#39;的行,即在行首添加#。 2. **提供命令**:使用sed命令。 - 常见方法是:`sed -i &#39;/pattern/ s/^/#/&#39; filename`。 - 具体到&#39;swap&#39;:`sed -i &#39;/swap/ s/^/#/&#39; filename`。 - 从引用[2],有`sed -i &#39;/ swap / s/^/# /g&#39; /etc/fstab`,注意空格,但用户没有指定空格,所以可能不需要。 - 为了精确,匹配包含&#39;swap&#39;的行,无论空格。 3. **解释命令**:解释每个部分。 - `/swap/`:匹配包含&#39;swap&#39;的行。 - `s/^/#/`:替换行首(^)为#。 - `-i`:直接修改文件(in-place edit)。 4. **添加引用**:自然地添加引用标识。例如,提到参考引用[1]或[2]。 5. **注意事项**:如备份文件,因为-i选项会修改文件。 6. **生成相关问题**:在最后,添加相关问题。 现在,构建回答: - 开头:确认用户需求。 - 中间:提供命令和解释。 - 结尾:生成相关问题。 用中文回答。 相关问题:基于用户问题,生成几个相关问题。例如: 1. 如何取消注释这些行? 2. sed命令的其他常见用法? 3. 如何匹配多个模式? 确保回答可靠:sed命令是标准工具,命令应该正确。 最终命令:推荐`sed -i &#39;/swap/ s/^/#/&#39; filename`。 从引用[2],有`sed -i &#39;/ swap / s/^/# /g&#39; /etc/fstab`,但用户可能不需要空格,所以使用更通用的。 在引用中,有`/ swap /`,但用户说"包含&#39;swap&#39;的行",所以可能不需要空格。使用`/swap/`。 在s命令中,`s/^/#/` 添加#在行首,没有空格。引用[2]有`# `,有空格,但用户可以调整。 提供基本命令。 添加引用:例如,"如参考引用[1]所示,使用&或\1来引用匹配内容。" 在引用[1],有`&#39;s/.*swap.*/#&/&#39;`,其中&是整个匹配行。 但在简单情况下,`s/^/#/` 就够用了。 为了通用性,可以使用`sed -i &#39;/swap/ s/^.*$/#&/&#39;`,但`s/^/#/`更简单。 `/swap/` 匹配包含swap的行,然后`s/^/#/`在行首添加#。 是的。 现在,写回答。</think>### 使用sed命令注释包含&#39;swap&#39;的行 要注释掉包含字符串"swap"的行,即在行首添加"#"符号,您可以使用sed(流编辑器)命令。sed是一个强大的文本处理工具,特别适合批量修改文件内容。下面我将逐步解释如何实现您的需求,确保命令安全可靠。注意:在执行修改命令前,建议备份文件,以防意外错误(例如,使用`cp filename filename.bak`)。 #### 步骤说明 1. **基本命令格式**: 使用sed的`-i`选项进行就地编辑(直接修改文件),并结合模式匹配和替换操作。 - 匹配包含"swap"的行:使用`/swap/`作为地址(address),它会选择所有包含子串"swap"的行(不区分大小写,默认区分大小写;如需忽略大小写,需添加`I`标志,但sed默认不支持,需用其他方法)。 - 在行首添加"#":使用替换命令`s/^/#/`,其中`^`表示行首,`#`是注释符号。 完整命令: ```bash sed -i &#39;/swap/ s/^/#/&#39; 文件名 ``` 例如,针对文件`/etc/fstab`: ```bash sed -i &#39;/swap/ s/^/#/&#39; /etc/fstab ``` 执行后,所有包含"swap"的行(如`/dev/mapper/centos-swap swap swap defaults 0 0`)会被改为`#/dev/mapper/centos-swap swap swap defaults 0 0`。 2. **添加空格(可选)**: 如果您希望在"#"后添加一个空格以提高可读性,可以修改替换部分为`s/^/# /`。例如: ```bash sed -i &#39;/swap/ s/^/# /&#39; 文件名 ``` 这会将行变为`# /dev/mapper/centos-swap swap swap defaults 0 0`。此方法在配置文件(如`/etc/fstab`)中常见,如参考引用[2]所示[^2]。 3. **处理正则表达式特殊字符**: - 如果"swap"出现在行中可能包含正则元字符(如`.`或`*`),建议转义模式。例如,使用`/swap/`一般足够,但更严谨的写法是`/.*swap.*/`(匹配整行包含"swap")。 - 引用匹配内容:您可以使用`&`或`\1`来引用整个匹配行。例如: ```bash sed -i &#39;/swap/ s/^.*$/#&/&#39; 文件名 ``` 这里`&`代表匹配的整行内容,等同于在行首添加"#"。类似方法在引用[1]中用于注释行[^1]。 4. **注意事项**: - **备份与测试**:`-i`选项直接修改文件。先测试命令而不修改文件,使用`sed -n &#39;/swap/ s/^/#/p&#39; 文件名`(`-n`和`p`仅打印修改行)。 - **空格处理**:引用[2]和[3]中使用了`/ swap /`(带空格),这要求"swap"前后有空格;但您的需求是"包含swap",所以`/swap/`更通用。如果需精确匹配单词(如避免匹配"swapon"),使用`/\<swap\>/`(GNU sed支持)。 - **选项`-i`和`-r`**:`-i`用于就地编辑;`-r`(或`-E`)支持扩展正则表达式,但可能需结合输出重定向(如引用[3]所述)[^3]。 - **文件权限**:确保您有文件写入权限(如使用`sudo`)。 #### 完整示例 假设文件`test.txt`内容为: ``` This is a swap line. Another line with swap. No match here. ``` 运行命令: ```bash sed -i &#39;/swap/ s/^/#/&#39; test.txt ``` 修改后内容: ``` #This is a swap line. #Another line with swap. No match here. ``` 此方法高效可靠,适用于Linux配置文件(如`/etc/fstab`)或日志处理。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值