题目链接:https://ac.nowcoder.com/acm/contest/12548/J
分析
数字所要去的位置会形成一个循环关系,如 2 3 4 1 ,会形成如下的循环关系:
2 要到 3 的位置,3 要到 4 的位置 4 要到 1 的位置:
我们如果将其进行对称交换,会发现下一轮只要再换一次就可以有序。
所以最多只要进行两轮交换。
代码
#include<bits/stdc++.h>
using namespace std;
int n,cnt;
int a[100005];
vector<int> ans[3],tmp;
map<int,int> vis;
int main()
{
int flag = 1;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i] != i) flag = 0;
}
if(flag == 1)
{
cout<<"0\n";
return 0;
}
cnt++;
vis.clear();
for(int i=1;i<=n;i++)
{
if(vis[i] == 1) continue;
if(i != a[i])
{
if(a[a[i]] == i)
{
int to = a[i];
if(vis[to] == 1) continue;
vis[i] = vis[to] = 1;
ans[cnt].push_back(i);
ans[cnt].push_back(to);
swap(a[i],a[to]);
}
else
{
tmp.clear();
int tt = 0;
for(int to=a[i];vis[to]!=1;to=a[to])
{
vis[to] = 1;
tmp.push_back(to);
}
for(int j=0,k=tmp.size()-1;j<k;j++,k--)
{
ans[cnt].push_back(tmp[j]);
ans[cnt].push_back(tmp[k]);
swap(a[tmp[j]], a[tmp[k]]);
}
}
}
}
flag = 1;
for(int i=1;i<=n;i++) if(a[i] != i)
{
flag = 0;
break;
}
if(flag == 1)
{
cout<<"1\n"<<(ans[1].size() / 2)<<" ";
for(int i=0;i<ans[1].size();i++) cout<<ans[1][i]<<" ";
cout<<"\n";
return 0;
}
cnt++;
for(int i=1;i<=n;i++)
{
if(i == a[i]) continue;
int to = a[i];
ans[cnt].push_back(i);
ans[cnt].push_back(to);
swap(a[i], a[to]);
}
cout<<"2\n";
cout<<(ans[1].size() / 2)<<" ";
for(int i=0;i<ans[1].size();i++) cout<<ans[1][i]<<" ";
cout<<"\n";
cout<<(ans[2].size() / 2)<<" ";
for(int i=0;i<ans[2].size();i++) cout<<ans[2][i]<<" ";
cout<<"\n";
//cout<<"ans: ";
//for(int i=1;i<=n;i++) cout<<a[i]<<" ";
return 0;
}