用map做个映射表,映射为-1的时候就是被访问了。我的方法是模拟整个过程
0不参加访问标记,因为0回到自己的位置会有两种情况
1、排序没有完成
2、排序完成
两种情况要分开讨论。
注意再访问是否被访问的时候因为是顺序访问,记录每次访问的终点,下次查询是否访问从那里开始,不然会超时。
…………………………更新线……………………………
重新写了一个模拟的方法,感觉比原先写的清爽一点
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#define MAX 100010
using namespace std;
int n;
int list[MAX];
map <int,int> num2pos;
set <int> non;
set <int> s;
int ans = 0;
bool cmp (int n1,int n2){
return n1 < n2;
}
int main(){
scanf("%d",&n);
int p0 = 1;
int p = 1;
for(int i = 1;i <= n;i++){
scanf("%d",&list[i]);
num2pos[list[i]] = p++;
if(list[i] == 0)
p0 = i;
}
sort(&list[1],&list[1] + n,cmp);
for(int i = 1;i <= n ;i++){
p = num2pos[list[i]];
if(p != i){
if(list[i]!= 0)
non.insert(list[i]);
}
}
while(!non.empty()){
if( p0 != 1){//0不在原点
//开始移动
int pn = list[p0];
p0 = num2pos[pn];
non.erase(non.find(pn));
}
else{//0在原点
int pn = *non.begin();
p0 = num2pos[pn];
num2pos[pn] = 1;
}
ans++;
}
printf("%d\n",ans);
return 0;
}
…………………………更新线完……………………………
#include <iostream>
#include <vector>
#include <map>
#define MAX 100010
using namespace std;
int n;
int list[MAX];
int c = 0;
int pos = 1;
map <int, int> n2r;
map <int, int> r2n;
void swap(){
#ifdef _DEBUG
cout << "-------------" << endl;
for (int i = 0; i < n; i++) {
cout << i << " : " << n2r[i] << endl;
}
#endif
if (n2r[0] != 0) { //0 不在0位 未排序完
int p1 = n2r[0]; //0的位置
int p2 = n2r[p1]; //0的位置对应的数的位置
c++;
n2r[0] = p2;
n2r[p1] = -1;//清除
swap();
}
else {//0在原点可能排完 也可能没排完
bool tag = false;
for (int i = pos; i < n; i++) {
if (n2r[i] > 0) { //没访问过
n2r[0] = i;
n2r[list[i]] = 0;
tag = true;
c++;
pos = i;
break;
}
}
if (tag == false) {//排序完成
cout << c << endl;
}
else
swap();
}
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
scanf("%d", &list[i]);
if(list[i] == i && list[i] != 0)//0不参与标记
n2r[list[i]] = -1;//在自己的位置不用交换
else
n2r[list[i]] = i;
}
swap();
return 0;
}