您的位置:首页 > 其它

UVA 10570 Meeting with Aliens 外星人聚会

2015-08-10 00:57 375 查看
题意:给你一个排列,每次可以交换两个整数(不一定要相邻),求最少交换次数把排列变成一个1~n的环形排列。(正反都算)

其实就是找环了,对于一个链状序列,最小交换次数等于不在对应位置的数字个数减去环的个数。

至于证明这里讲的比较详细:http://www.dewen.io/q/7967#ans16319

所以只要枚举一下环的起点就好了,dfs找环就行了。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e3+233;
#define bug(x) cout<<#x<<'='<<x<<endl;
int a[maxn];

bool vis[maxn];

int cnt,s;
void dfs(int u)
{
if(vis[u]) return;
cnt++;
vis[u] = true;
dfs(a[u+s]);
}
int n;

void dfs2(int u)
{
if(vis[n-1-u]) return;
cnt++;
vis[n-1-u] = true;
dfs2(a[n-1-u+s]);
}

int main()
{
//freopen("in.txt","r",stdin);
while(~scanf("%d",&n)&&n){
for(int i = 0; i < n; i++){
scanf("%d",a+i); a[i+n] = --a[i];
}

int ans = INT_MAX;
for( s = 0; s < n; s++){
int cur = 0;
memset(vis,0,sizeof(vis));
for(int i = 0; i < n; i++)if(!vis[i]) {
if(a[i+s] != i) {
vis[i] = true; cnt = 0;
dfs(a[i+s]);
cur += cnt;
}else vis[i] = true;
}
ans = min(ans,cur);
}
reverse(a,a+2*n);
for( s = 0; s < n; s++){
int cur = 0;
memset(vis,0,sizeof(vis));
for(int i = 0; i < n; i++)if(!vis[i]) {
if(a[i+s] != i) {
vis[i] = true; cnt = 0;
dfs(a[i+s]);
cur += cnt;
}else vis[i] = true;
}
ans = min(ans,cur);
}

printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: