篝火晚会 题解

一道关于环形座位调整的题目,难点在于理解题意。题目要求按照同学们的意愿重新排列坐位,通过特定命令调整顺序。正确理解是命令中的编号可以代表任意同学,目标是找到使序列符合要求的最小步骤。可以转化为序列转换问题,作者用个人思路成功解决,并未涉及置换群等高级概念。

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

这道题,我感觉最大的难点在于对题目的理解,不知道是我理解能力有问题还是出题人叙述有问题,我花了很长的时间弄清楚题意,下面,我们把无用的信息筛去,从题意方面重新理解这道题。

  一共有n个同学,编号从1到n,初始状态这n个人按1,2,……,n的顺序坐成一个环,每个人都希望与自己相邻的人坐在一起,如何下令调整同学的次序,形成新的一个圈,是之符合同学们的意愿。可以下达这样的命令(b1,b2,b3......bm),这里的m的值由我们决定,每次命令的m的值可以不同,这个命令的作用是移动编号是b1,b2,…… bm -1,bm的这m个同学的位置。要求b1换到b2的位置上,b2换到b3的位置上,……,要求bm换到b1的位置上。

我第一次理解成下达的命令只能从移动从1开始到m的同学(实际上不就是这样吗?) 但正确的理解应该是b1可以代表任何编号的童鞋。

所以我们可以这样想,对于一个打乱的序列,我们总有一种命令,可以一次使之变成我们想要的顺序,只要我们这个命令上的编号顺序进行一些设计。

我们可以根据每个人的意愿,生成一个符合每个人要求的环,如果不能生成,就输出-1。

接下来问题就转化为初始序列转化成目标序列需要的最少步数问题了。网上的一些资料居然还用到了置换群的知识点,我是没想到这么高深的做法,只是按照自己的思路写就AC了。

相对位置,恩,明白了吧。

#include<cstdio>
#include<iostream>
#include<string.h>
using namespace std;
const int maxn=50050;
int n,b[maxn],a[maxn][2];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i][1],&a[i][2]);
	}
	b[1]=1;
	b[2]=a[1][1];
	int t1=b[1],t2=b[2];
	for(int i=3;i<=n;t1=t2,t2=b[i],i++)
	{
		if(a[t2][1]==t1)b[i]=a[t2][2]; 
		else 
		if(a[t2][2]==t1)b[i]=a[t2][1];
		else
		{
			printf("-1");
			return 0;
		}
	} 
	if(b[n]!=a[1][2])
	{
		printf("-1");
		return 0;
	}
	
	memset(a,0,sizeof(a));  //a数组之前的作用是记录第i个位同学喜欢相邻的人 现在a数组已经没用了,我们可以“废物利用” 
	int t=0;
	for(int i=1;i<=n;i++)  //统计顺时针、逆时针相对位置相同的最多的数 
	{
		a[(b[i]-i+n)%n][1]++;  //  顺时针,加上n是避免出现负数,因为是环,所以用%n来循环。 
		a[(b[i]+i)%n][2]++;	
	}
	for(int i=1;i<=n;i++) 
	{
		if(a[i][1]>t)t=a[i][1];
		if(a[i][2]>t)t=a[i][2];
	}
	
	printf("%d",n-t);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值