题目链接:http://codeforces.com/problemset/problem/698/B点击打开链接
先判断给你的序列中有多少个环 有多少个独立点
将所有环的其中一个点 以及所有独立点连到其中一个独立点上 就能保证最小
可以用并查集判断环和独立点
如果都是环就随便选一个环的一个当根 将其他的环的各一个点连到这个根上
然后判断跟原序列多少个不同
#include <iostream>
#include <stdio.h>
#include <limits.h>
#include <stack>
#include <algorithm>
#include <queue>
#include <string.h>
#include <set>
#include <vector>
using namespace std;
vector <int> s;
int pre[222222];
int ppre[222222];
int pppre[222222];
int book[222222];
int findx(int x)
{
set <int > s;
s.clear();
int r=x;
while(pre[r]!=r)
{
if(s.count(r))
{
book[r]=1;
pre[r]=r;
break;
}
s.insert(r);
r=pre[r];
}
int i=x,j;
while(pre[i]!=r)
{
j=pre[i];
pre[i]=r;
i=j;
}
return r;
}
set <int > ss;
set <int > ::iterator it;
int main()
{
ss.clear();
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int mid;
scanf("%d",&mid);
pre[i]=mid;
ppre[i]=mid;
pppre[i]=mid;
}
for(int i=1;i<=n;i++)
{
pre[i]=findx(i);
}
for(int i=1;i<=n;i++)
{
if(pre[i]==i)
pre[i]=i;
else
pre[i]=ppre[i];
}
for(int i=1;i<=n;i++)
if(pre[i]==i)
ss.insert(i);
int flag=0;
for(it=ss.begin();it!=ss.end();it++)
if(book[(*it)]!=1)
{
flag=(*it);
}
if(flag)
{
for(it=ss.begin();it!=ss.end();it++)
pre[(*it)]=flag;
}
else
{
for(it=ss.begin();it!=ss.end();it++)
pre[(*it)]=(*ss.begin());
}
int num=0;
for(int i=1;i<=n;i++)
if(pre[i]!=pppre[i])
num++;
printf("%d\n",num);
for(int i=1;i<=n;i++)
cout << pre[i] << " ";
}