南邮 OJ 1871 Sorting Problem II

本文探讨了一种排序问题,即在对特定排列的数字进行从小到大排序时,如何在消耗特定数量的体力(交换操作)下完成排序。文章详细介绍了算法逻辑,并通过实例演示了如何判断是否存在这样的排序方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Sorting Problem II

时间限制(普通/Java) : 1000 MS/ 2000 MS          运行内存限制 : 16384 KByte
总提交 : 325            测试通过 : 43 

比赛描述

openxxx喜欢一切有序的事物,现在有一串数字,openxxx希望对这串数字从小到大进行排序(实现非递减序)。

openxxx可以交换任意两个数字,每做一次交换,就要消耗openxxx一格体力值,openxxx希望恰好在消耗了K格体力值的情况下完成排序,请你判断是否可能存在这样的情况。




输入

多组测试数据,每组数据第一行包含一个正整数N(1<=N<=500)表示这串数字的个数,第二行包含N个正整数恰好是1~N的某一排列,相邻数字之间用一个空格隔开。第三行包含一个正整数M(1<=M<=500),接下来M行,每行包含一个非负整数K(0<=K<=50000),其含义见题目描述。


输出

每组测试数据对应M行输出,每行输出一个字符串 “YES”或者“NO”(不包括双引号),存在恰好消耗了K格体力值的情况下完成排序则输出“YES”,否则输出“NO”。


样例输入

2
2 1
2
0
1

样例输出

NO
YES

题目来源

2012南京邮电大学第四届大学生程序设计大赛(预赛)




/* Wrong Answer at Test 1
// 思路: 最少交换次数 = n-circle_count,circle_count为环的个数
#include<iostream>

#define MAX_N 501
int a[MAX_N];
bool vst[MAX_N];

int main(){
	freopen("test.txt","r",stdin);
	int n,i,circle_count,count,m,k;
	while(scanf("%d",&n)==1){
		for(i=1;i<=n;i++){
			scanf("%d",a+i);
		}
		memset(vst,0,sizeof(vst));
		circle_count = 0;
		count = 0;
		while(count<n){
			for(i=1;i<n;i++){
				if(!vst[i]){
					break;
				}
			}
			vst[i] = 1;
			count++;
			while(!vst[a[i]]){
				i = a[i];
				vst[i] = 1;
				count++;
			}
			circle_count++;
		}
//		printf("circle_count = %d\n",circle_count);
		scanf("%d",&m);
		while(m--){
			scanf("%d",&k);
			if(k>=(n-circle_count) && ((k-(n-circle_count))&1)==0){
				printf("YES\n");
			}else{
				printf("NO\n");
			}
		}
	}
}
*/


// 思路: 最少交换次数 = n-circle_count,circle_count为环的个数
#include<iostream>

#define MAX_N 501
int a[MAX_N];
bool vst[MAX_N];

int main(){
//	freopen("test.txt","r",stdin);
	int n,i,circle_count,count,m,k;
	while(scanf("%d",&n)==1){
		for(i=1;i<=n;i++){
			scanf("%d",a+i);
		}
		memset(vst,0,sizeof(vst));
		circle_count = 0;
		count = 0;
		while(count<n){			// 直到所有节点被访问过为止
			for(i=1;i<=n;i++){	// WA1
				if(!vst[i]){
					break;
				}
			}
			vst[i] = 1;			// 先找到第一个未被访问过的点
			count++;
			while(!vst[a[i]]){
				i = a[i];
				vst[i] = 1;
				count++;		// 访问过的节点总数
			}
			circle_count++;
		}
//		printf("circle_count = %d\n",circle_count);
		scanf("%d",&m);
		while(m--){
			scanf("%d",&k);
			if(k>=(n-circle_count) && ((k-(n-circle_count))&1)==0){	//大于最少次数,且相差偶数
				printf("YES\n");
			}else{
				printf("NO\n");
			}
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值