排队(小思维题)

博客探讨了一种O(1)复杂度的解决方案,用于解决在大量数据中通过最少交换次数使编号与顺序号一致的问题。通过找到未在环中的元素并构建环,计算环的边数来确定最小交换次数。这种方法避免了动态规划可能导致的时间超限问题。
摘要由CSDN通过智能技术生成

时间限制: 1 Sec 内存限制: 128 MB

题目描述
乐乐的 n 位朋友都拥有唯一的一个编号,编号分别为 1 至 n。某天按到达的时间顺序又给了一个顺序号,此时发现顺序号与多数的朋友编号不一致。乐乐想:如果俩俩交换顺序号,使得每位朋友的编号与顺序号相同,则最少需要交换几次?

输入
包含两行:
第一行只有一个正整数:n,表示乐乐朋友的人数
第二行共有 n 个正整数,分别表示按顺序到达的朋友编号
输出
只有一行且只有一个正整数:最少的交换次数
样例输入 Copy
5
4 2 1 5 3
样例输出 Copy
3

提示
对于 30%的数据, 1 <= n <= 100
对于 80%的数据, 1 <= n <= 10 000
对于 100%的数据, 1 <= n <= 100 000

大意:给出一组数据,编号是乱的,两两之间交换(可以不相邻),至少多少次可以使其有序

起初看着像动态规划,就没往下想。结束一交流发现,数据太大,如果是动态规划的话,二重循环肯定超时!
既然不是动态规划,这么大的数据,就要用O(1)的做法了。

思路:对每个不同的数据,直接跳到其归属的位置(调换),而那个位置的值又要跳到其归属的位置,
一直跳,最终,就会跳到一开始那个数据的位置,这样,就构成了一个环。
而这个环的边数,就是最小的调换次数。
对于这组数据中的所有的环,求出边数和就是这组数据调至有序的最少次数。

Code:

#include<iostream>
using namespace std;

const int N=100010;
int n,a[N],t,cnt;
bool f[N];

int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(a[i]!=i) ;
	}
	for(int i=1;i<=n;i++){
		if(a[i]!=i&&!f[i]){ //找出 编号不同&&不在之前的环中 的一个数据 
			t=i;
			int tt=t;
			while(a[tt]!=t){ //跳环 
				tt=a[tt];
				f[tt]=true; //跳过的地方就会变成有序的,标记,下次就不会找到了 
				cnt++;
			}
		}
	}
	
	cout<<cnt;
	return 0;
}

如果哪里不明白或有错误的话,欢迎留言讨论~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值