给出你长度为 n n n的一个序列(n的全排列),让你通过交换两个数来让他变成下标和数值对应。每一场可以包含多对,但是每个点只能用一次。问你最少需要多少场能使得他变成我们需要的序列(单调递增),并且输出每次操作的两个点。
我们对样例先进行分析一下来理解题意
4
4 3 2 1
我们可以通过换(4,1),(3,2) {这里指的是数值}
因为没有一个点使用俩遍,所以我们可以通过一次操作来实现。
然后我们进一步分析,每个位置有两个属性分别是:下标和值
这里是一开始的错误思路:
一开始以为最多是3场:
那么我们可以其实用正常的思路就是确定一个点两两互换
如果我们输入的是这样的
2 3 4 5 6 1
那么我们画出图形就是圆里是值,外面是下标,线是下标应该对应的值
那么我们很容易想到把1和2互换(代表里面的值),因为1和2都用过了,所以同一场上不能在换了,我还可以换3和4,5和6换完之后变成,
整理一下就变成这样的:
那么我们在随便换一个假如是2和4,那么就会把2归位 这就是第二场要做的,
第三场要做的就是4和6互换,
但其实这并不是最优的,我们先了解一下这个:
如果
这样的我们就可以一步互换就可归位,那么我们就可以尽量将原图一场归成这样的,那么再进行一场就可以将所有归位,那么我们怎么实现是个问题
还拿上图来说:
我们要凑对的话,我们发现隔一个交换就可以实现,像我们像构造1和2这一对,我们就交换1和3(里面的值);
就变成了这样
3这个地方打个星说明他用过这一场我们不能再用,我们看上一步我们并没有用到1,但就把1和2凑出来了,那么我们同理把3放中间,交换3两端的,就可以凑出3和6,剩下4和5自成一对。
这是偶数情况,奇数情况也是这样的,只不过最后一下会让独立出来的一个归位。
int main() {
n=read;
rep(i,1,n){
a[i]=read;
}
for(int i=1;i<=n;i++){///起点
if(!vis[i]){
int idx=0,tmp=i;
while(!vis[tmp]){
vis[tmp]=1;
b[++idx]=tmp;
tmp=a[tmp];
}
if(idx>=2){
int l=2,r=idx;
while(l<r){
v[1].push_back({b[l],b[r]});
swap(b[l],b[r]);
l++,r--;
}
l=1,r=idx;
while(l<r){
v[2].push_back({b[l],b[r]});
l++,r--;
}
}
}
}
int res=0;
if(v[1].size()) res++;
if(v[2].size()) res++;
printf("%d\n",res);
if(res==0){
return 0;
}
for(int i=1;i<=2;i++){
if(!v[i].size()) continue;
printf("%d ",v[i].size());
for(int j=0;j<v[i].size();j++)
printf("%d %d ",v[i][j].first,v[i][j].second);
puts("");
}
return 0;
}
本文解法基于性质二叉搜索树的中序遍历为 递增序列 。 将 二叉搜索树 转换成一个...
通常,在asp中进行的form表单提交的数据都被写进数据库管理系统中去,如果你想要...
HTML 文本格式化标签 标签 描述 b 定义粗体文本 em 呈现为被强调的文本 i 定义斜...
提问: 复制代码 代码如下: script type=text/javascript src=http://fw.qq.com/...
Struts2 OGNL调用公共静态方法 一直以来都知道Struts2的OGNL支持在前台调用后台...
ajax请求是一种无刷新式的用户体验,可以发送GET和POST两种异步请求,现记录如下...
一、前言 this关键字是JavaScript中最复杂的机制之一。它是一个很特别的关键字,...
前言 ??今天我一个人待在实验室里没有在做题目没有在看教学视频我只想好好想想我...
很多年前,人们就将windows定义为更适合娱乐的操作系统,相比于mac系统很少有人...
一:访问或添加request/session/application属性 复制代码 代码如下: public Str...