目录
1 问题描述
有 N 个瓶子,编号 1 ~ N,放在架子上。
比如有 5 个瓶子:
2 1 3 5 4
要求每次拿起 2 个瓶子,交换它们的位置。
经过若干次后,使得瓶子的序号为:
1 2 3 4 5
对于这么简单的情况,显然,至少需要交换 2 次就可以复位。
如果瓶子更多呢?你可以通过编程来解决。
输入描述
输入格式为两行:
第一行: 一个正整数 N(N<10000), 表示瓶子的数目
第二行: N 个正整数,用空格分开,表示瓶子目前的排列情况。
输出描述
输出数据为一行一个正整数,表示至少交换多少次,才能完成排序。
输入输出样例
示例
输入
5
3 1 2 5 4
输出
3
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
2 直接交换法
不知道为什么这个办法也可以满分
#include <bits/stdc++.h>
using namespace std;
int n;
int ping[10000];
int temp;
int cnt;
int x,i;
int main()
{
cin>>n;
for(i=1;i<=n;i++)
{
cin>>ping[i];
}
for(i=1;i<=n;i++)
{
if(ping[i]!=i)
{
temp=ping[i];
for(x=i+1;x<=n;x++)
{
if(i==ping[x]) break;
}
ping[i]=ping[x];
ping[x]=temp;
cnt++;
}
}
cout<<cnt;
return 0;
}
3 图论
示例:
瓶子: 2 1 3 5 4
序号: 1 2 3 4 5
根据如上情况构成一张图:
如果已经排好序,那么一定是五个自环的关系,环数=5
每交换环内的两个瓶子,环数+1
最开始有3个环
那么需要交换2次
结论:有n个瓶子,起初构成k个环,需要交换n-k次
代码:
#include <bits/stdc++.h>
using namespace std;
int n;
int a[10000];
bool vis[10000]; // 判断是否成环
int cnt;
int main()
{
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++)
{
if(!vis[i])//判断是否浏览过
{
cnt ++; // 记录环数 31254
for(int j = i; !vis[j]; j = a[j])//第一个瓶子是3,然后找a[3]对应的瓶子是2,然后找a[2]对应的瓶子是1,发现a[1]浏览过,这个环构建完毕,然后继续构建下一个环
{
vis[j] = true; // 将该环上的所有的数标记为true
}
}
}
cout << n - cnt << endl; // 最后输出 n - cnt 即可
return 0;
}