【排序】我不和你玩

第2题:我不和你玩

 

【题目描述】

在一个N*N矩阵的世界里生活着X,C,R三种元素。他们开始相处得很融洽。但后来有一天:

X:C们太不够意思了,最近他们经常作出不利于我们团结的事情。

R:对啊对啊,简直令人发指。

X:我们以后不跟他们玩了。

R:好!

于是X和R决定抵制C,要把所有的C赶到矩阵的左下角去。但是移动一个一个的元素是很费劲的。所以每次操作他们只能交换相邻的两个整行(包括这两行的X和R)。

你需要求出为了把所有的C移到左下角去(即所有的C的坐标x行y列均满足x小于等于y),所需要的最少操作步数。输入数据保证有解。

 

【输入格式】

第一行一个正整数T,代表有T组数据。

对于每组数据,第一行一个正整数N,代表矩阵的规模。然后接下来的N行每行有N个字符,必然是X,C,R中的一个。

 

【输出格式】

输出T行,每行一个整数,顺次为每组数据的最少操作步数。

 

【数据范围】

对于30分的数据,N小于等于8。

对于100分的数据,N小于等于40,T小于等于6。

 

【输入样例】

3

2

CR

CC

3

XRC

CXX

RCX

4

CCCX

CCXX

CCXX

CXXX

【输出样例】

0

2

4


这个是冒泡排序的模型。

首先可以发现,每一行都只和这一行最右边的那个C有关,

所以我们记录下每一行最右边的C位置。


观察发现,比较类似于冒泡排序(相邻交换)的思路,所以我们来验证。

从上到下找到不能满足条件的一行i,在不改变原来已经满足条件的行的情况下,我们选择最近(必定这样交换次数更小)的行j,且j移动到i之后,i移动到j之后能满足条件,且交换路径中的其它行,因为都是往下调整,所以只会更优不会更差。可以发现,这一步既满足了i,同时不改变原有的满足条件,因此必定是最小的步数使i满足条件。

同理的,每一个i我们都能找到局部最优的调整方法,将所有行都调整到满足条件的位置,就实现了全局最优。

所以冒泡排序是正确的,只是不同的,我们需要找到最近一个能够交换的,把它交换上来。


#include <cstdio>
#include <string>
#include <cstring>

long maxj[60];
char map[60][60];

long getint()
{
	long rs=0;bool sgn=1;char tmp;
	do tmp = getchar();
	while (!isdigit(tmp)&&tmp-'-');
	if (tmp == '-'){tmp=getchar();sgn=0;}
	do rs=(rs<<3)+(rs<<1)+tmp-'0';
	while (isdigit(tmp=getchar()));
	return sgn?rs:-rs;	
}

int main()
{
	freopen("play.in","r",stdin);
	freopen("play.out","w",stdout);

	long T = getint();
	while (T --)
	{
		long ans = 0;
		long n = getint();
		memset(maxj,0,sizeof maxj);
		for (long i=1;i<n+1;i++)
		{
			for (long j=1;j<n+1;j++)
			{
				do map[i][j]=getchar();
				while (map[i][j]!='C'&&map[i][j]!='R'&&map[i][j]!='X');
				if (map[i][j] == 'C')
					maxj[i] = j;
			}
		}

		for (long i=1;i<n+1;i++)
		{
			if (maxj[i] > i)
			{
				long pos = 0;
				for (long j=i+1;j<n+1;j++)
				{
					if (maxj[j] <= i)
					{
						pos = j;
						break;
					}
				}
				for (long j=pos-1;j>i-1;j--)
				{
					ans ++;
					long tmp = maxj[j];
					maxj[j] = maxj[j+1];
					maxj[j+1] = tmp;
				}
			}
		}
		printf("%ld\n",ans);
	}

	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值