您的位置:首页 > 其它

UVa 10570 外星人聚会

2017-03-01 15:04 211 查看
https://vjudge.net/problem/UVA-10570

题意:
输入1~n的排列,每次可以交换两个整数,求出最少交换次数使之变成有序的环状序列。

思路:
主要的解题方法就是寻找置换环,举个例子来说吧,因为起点可以是任意位置,我们假设起点在1的位置。

比如说 5 1 3 4 2 7 6 8 ,第一个数5应该在第5个位置,此时第5个位置上为2,而2应该在第2个位置,此时第2个位置上为1,而1应该在第一个位置即5的位置。因此{5,1,2}构成了一个置换群,别的也是这样的分析,总共可以分为{5,1,2},{3},{4},{6,7},{8}5个置换环,所以交换次数为8-5=3。这个也很好理解,如果每个数都在正确的位置上,那么每个数各自构成一个置换环,那么相减之后就是0了。

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;

int n;
int a[1100],b[1100];
int vis[1100];

void dfs(int k, int start)
{
if (vis[k])     return;
vis[k] = 1;
int t = a[k + start];
dfs(t, start);
}

void dfs2(int k, int start)
{
if (vis[k])     return;
vis[k] = 1;
int t = a[start-k];
dfs2(t, start);
}

int main()
{
//freopen("D:\\txt.txt", "r", stdin);
while (cin >> n && n)
{
int num;
for (int i = 0; i < n; i++)
{
cin >> a[i];
a[i + n] = a[i];
}
int count = 0;

//正序
for (int i = 0; i < n; i++)   //枚举起点
{
memset(vis, 0, sizeof(vis));
num = 0;
for (int j = 0; j < n; j++)
{
if (!vis[j])
{
num++;
dfs(j, i);
}
}
count = max(num, count);
}

//逆序
for (int i = 2 * n - 1; i >= n;i--)   //枚举起点
{
memset(vis, 0, sizeof(vis));
num = 0;
for (int j = 0; j < n; j++)
{
if (!vis[j])
{
num++;
dfs2(j, i);
}
}
count = max(num, count);
}
int ans = n - count;
cout << ans << endl;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: